mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-25 08:52:12 +00:00
refactor: share parsed channel allowlist prompts
This commit is contained in:
@@ -277,6 +277,12 @@ The `ChannelSetupWizard` type supports `credentials`, `textInputs`,
|
||||
See bundled plugins (e.g. `extensions/discord/src/channel.setup.ts`) for
|
||||
full examples.
|
||||
|
||||
For DM allowlist prompts that only need the standard
|
||||
`note -> prompt -> parse -> merge -> patch` flow, prefer the shared setup
|
||||
helpers from `openclaw/plugin-sdk/setup`: `createPromptParsedAllowFromForAccount(...)`,
|
||||
`createTopLevelChannelParsedAllowFromPrompt(...)`, and
|
||||
`createNestedChannelParsedAllowFromPrompt(...)`.
|
||||
|
||||
For optional setup surfaces that should only appear in certain contexts, use
|
||||
`createOptionalChannelSetupSurface` from `openclaw/plugin-sdk/channel-setup`:
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {
|
||||
createAllowFromSection,
|
||||
createPromptParsedAllowFromForAccount,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
formatDocsLink,
|
||||
promptParsedAllowFromForAccount,
|
||||
type ChannelSetupDmPolicy,
|
||||
type ChannelSetupWizard,
|
||||
type OpenClawConfig,
|
||||
type WizardPrompter,
|
||||
} from "openclaw/plugin-sdk/setup";
|
||||
import {
|
||||
listBlueBubblesAccountIds,
|
||||
@@ -49,44 +48,35 @@ function validateBlueBubblesAllowFromEntry(value: string): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
async function promptBlueBubblesAllowFrom(params: {
|
||||
cfg: OpenClawConfig;
|
||||
prompter: WizardPrompter;
|
||||
accountId?: string;
|
||||
}): Promise<OpenClawConfig> {
|
||||
return await promptParsedAllowFromForAccount({
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
defaultAccountId: resolveDefaultBlueBubblesAccountId(params.cfg),
|
||||
prompter: params.prompter,
|
||||
noteTitle: "BlueBubbles allowlist",
|
||||
noteLines: [
|
||||
"Allowlist BlueBubbles DMs by handle or chat target.",
|
||||
"Examples:",
|
||||
"- +15555550123",
|
||||
"- user@example.com",
|
||||
"- chat_id:123",
|
||||
"- chat_guid:iMessage;-;+15555550123",
|
||||
"Multiple entries: comma- or newline-separated.",
|
||||
`Docs: ${formatDocsLink("/channels/bluebubbles", "bluebubbles")}`,
|
||||
],
|
||||
message: "BlueBubbles allowFrom (handle or chat_id)",
|
||||
placeholder: "+15555550123, user@example.com, chat_id:123",
|
||||
parseEntries: (raw) => {
|
||||
const entries = parseBlueBubblesAllowFromInput(raw);
|
||||
for (const entry of entries) {
|
||||
if (!validateBlueBubblesAllowFromEntry(entry)) {
|
||||
return { entries: [], error: `Invalid entry: ${entry}` };
|
||||
}
|
||||
const promptBlueBubblesAllowFrom = createPromptParsedAllowFromForAccount({
|
||||
defaultAccountId: (cfg) => resolveDefaultBlueBubblesAccountId(cfg),
|
||||
noteTitle: "BlueBubbles allowlist",
|
||||
noteLines: [
|
||||
"Allowlist BlueBubbles DMs by handle or chat target.",
|
||||
"Examples:",
|
||||
"- +15555550123",
|
||||
"- user@example.com",
|
||||
"- chat_id:123",
|
||||
"- chat_guid:iMessage;-;+15555550123",
|
||||
"Multiple entries: comma- or newline-separated.",
|
||||
`Docs: ${formatDocsLink("/channels/bluebubbles", "bluebubbles")}`,
|
||||
],
|
||||
message: "BlueBubbles allowFrom (handle or chat_id)",
|
||||
placeholder: "+15555550123, user@example.com, chat_id:123",
|
||||
parseEntries: (raw) => {
|
||||
const entries = parseBlueBubblesAllowFromInput(raw);
|
||||
for (const entry of entries) {
|
||||
if (!validateBlueBubblesAllowFromEntry(entry)) {
|
||||
return { entries: [], error: `Invalid entry: ${entry}` };
|
||||
}
|
||||
return { entries };
|
||||
},
|
||||
getExistingAllowFrom: ({ cfg, accountId }) =>
|
||||
resolveBlueBubblesAccount({ cfg, accountId }).config.allowFrom ?? [],
|
||||
applyAllowFrom: ({ cfg, accountId, allowFrom }) =>
|
||||
setBlueBubblesAllowFrom(cfg, accountId, allowFrom),
|
||||
});
|
||||
}
|
||||
}
|
||||
return { entries };
|
||||
},
|
||||
getExistingAllowFrom: ({ cfg, accountId }) =>
|
||||
resolveBlueBubblesAccount({ cfg, accountId }).config.allowFrom ?? [],
|
||||
applyAllowFrom: ({ cfg, accountId, allowFrom }) =>
|
||||
setBlueBubblesAllowFrom(cfg, accountId, allowFrom),
|
||||
});
|
||||
|
||||
function validateBlueBubblesServerUrlInput(value: unknown): string | undefined {
|
||||
const trimmed = String(value ?? "").trim();
|
||||
|
||||
@@ -3,12 +3,12 @@ import {
|
||||
createTopLevelChannelAllowFromSetter,
|
||||
createTopLevelChannelDmPolicy,
|
||||
createTopLevelChannelGroupPolicySetter,
|
||||
createTopLevelChannelParsedAllowFromPrompt,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
formatDocsLink,
|
||||
hasConfiguredSecretInput,
|
||||
mergeAllowFromEntries,
|
||||
patchTopLevelChannelConfigSection,
|
||||
promptParsedAllowFromForAccount,
|
||||
promptSingleChannelSecretInput,
|
||||
splitSetupEntries,
|
||||
type ChannelSetupDmPolicy,
|
||||
@@ -93,30 +93,22 @@ function isFeishuConfigured(cfg: OpenClawConfig): boolean {
|
||||
return topLevelConfigured || accountConfigured;
|
||||
}
|
||||
|
||||
async function promptFeishuAllowFrom(params: {
|
||||
cfg: OpenClawConfig;
|
||||
prompter: Parameters<NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]>>[0]["prompter"];
|
||||
}): Promise<OpenClawConfig> {
|
||||
return await promptParsedAllowFromForAccount({
|
||||
cfg: params.cfg,
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
prompter: params.prompter,
|
||||
noteTitle: "Feishu allowlist",
|
||||
noteLines: [
|
||||
"Allowlist Feishu DMs by open_id or user_id.",
|
||||
"You can find user open_id in Feishu admin console or via API.",
|
||||
"Examples:",
|
||||
"- ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"- on_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
],
|
||||
message: "Feishu allowFrom (user open_ids)",
|
||||
placeholder: "ou_xxxxx, ou_yyyyy",
|
||||
parseEntries: (raw) => ({ entries: splitSetupEntries(raw) }),
|
||||
getExistingAllowFrom: ({ cfg }) => cfg.channels?.feishu?.allowFrom ?? [],
|
||||
mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed),
|
||||
applyAllowFrom: ({ cfg, allowFrom }) => setFeishuAllowFrom(cfg, allowFrom),
|
||||
});
|
||||
}
|
||||
const promptFeishuAllowFrom = createTopLevelChannelParsedAllowFromPrompt({
|
||||
channel,
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
noteTitle: "Feishu allowlist",
|
||||
noteLines: [
|
||||
"Allowlist Feishu DMs by open_id or user_id.",
|
||||
"You can find user open_id in Feishu admin console or via API.",
|
||||
"Examples:",
|
||||
"- ou_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"- on_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
],
|
||||
message: "Feishu allowFrom (user open_ids)",
|
||||
placeholder: "ou_xxxxx, ou_yyyyy",
|
||||
parseEntries: (raw) => ({ entries: splitSetupEntries(raw) }),
|
||||
mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed),
|
||||
});
|
||||
|
||||
async function noteFeishuCredentialHelp(
|
||||
prompter: Parameters<NonNullable<ChannelSetupWizard["finalize"]>>[0]["prompter"],
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
applySetupAccountConfigPatch,
|
||||
createNestedChannelParsedAllowFromPrompt,
|
||||
createNestedChannelDmPolicy,
|
||||
DEFAULT_ACCOUNT_ID,
|
||||
formatDocsLink,
|
||||
mergeAllowFromEntries,
|
||||
migrateBaseNameToDefaultAccount,
|
||||
patchNestedChannelConfigSection,
|
||||
splitSetupEntries,
|
||||
type ChannelSetupDmPolicy,
|
||||
type ChannelSetupWizard,
|
||||
@@ -24,30 +24,17 @@ const ENV_SERVICE_ACCOUNT_FILE = "GOOGLE_CHAT_SERVICE_ACCOUNT_FILE";
|
||||
const USE_ENV_FLAG = "__googlechatUseEnv";
|
||||
const AUTH_METHOD_FLAG = "__googlechatAuthMethod";
|
||||
|
||||
async function promptAllowFrom(params: {
|
||||
cfg: OpenClawConfig;
|
||||
prompter: Parameters<NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]>>[0]["prompter"];
|
||||
}): Promise<OpenClawConfig> {
|
||||
const current = params.cfg.channels?.googlechat?.dm?.allowFrom ?? [];
|
||||
const entry = await params.prompter.text({
|
||||
message: "Google Chat allowFrom (users/<id> or raw email; avoid users/<email>)",
|
||||
placeholder: "users/123456789, name@example.com",
|
||||
initialValue: current[0] ? String(current[0]) : undefined,
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
});
|
||||
const parts = splitSetupEntries(String(entry));
|
||||
const unique = mergeAllowFromEntries(undefined, parts);
|
||||
return patchNestedChannelConfigSection({
|
||||
cfg: params.cfg,
|
||||
channel,
|
||||
section: "dm",
|
||||
enabled: true,
|
||||
patch: {
|
||||
policy: "allowlist",
|
||||
allowFrom: unique,
|
||||
},
|
||||
});
|
||||
}
|
||||
const promptAllowFrom = createNestedChannelParsedAllowFromPrompt({
|
||||
channel,
|
||||
section: "dm",
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
enabled: true,
|
||||
message: "Google Chat allowFrom (users/<id> or raw email; avoid users/<email>)",
|
||||
placeholder: "users/123456789, name@example.com",
|
||||
parseEntries: (raw) => ({
|
||||
entries: mergeAllowFromEntries(undefined, splitSetupEntries(raw)),
|
||||
}),
|
||||
});
|
||||
|
||||
const googlechatDmPolicy: ChannelSetupDmPolicy = createNestedChannelDmPolicy({
|
||||
label: "Google Chat",
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { DmPolicy } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
|
||||
import {
|
||||
createAllowFromSection,
|
||||
promptParsedAllowFromForAccount,
|
||||
createPromptParsedAllowFromForAccount,
|
||||
setSetupChannelEnabled,
|
||||
} from "openclaw/plugin-sdk/setup";
|
||||
import type { ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup";
|
||||
@@ -52,36 +52,27 @@ function normalizeGroupEntry(raw: string): string | null {
|
||||
return `#${normalized.replace(/^#+/, "")}`;
|
||||
}
|
||||
|
||||
async function promptIrcAllowFrom(params: {
|
||||
cfg: CoreConfig;
|
||||
prompter: WizardPrompter;
|
||||
accountId?: string;
|
||||
}): Promise<CoreConfig> {
|
||||
return await promptParsedAllowFromForAccount({
|
||||
cfg: params.cfg,
|
||||
accountId: params.accountId,
|
||||
defaultAccountId: resolveDefaultIrcAccountId(params.cfg),
|
||||
prompter: params.prompter,
|
||||
noteTitle: "IRC allowlist",
|
||||
noteLines: [
|
||||
"Allowlist IRC DMs by sender.",
|
||||
"Examples:",
|
||||
"- alice",
|
||||
"- alice!ident@example.org",
|
||||
"Multiple entries: comma-separated.",
|
||||
],
|
||||
message: "IRC allowFrom (nick or nick!user@host)",
|
||||
placeholder: "alice, bob!ident@example.org",
|
||||
parseEntries: (raw) => ({
|
||||
entries: parseListInput(raw)
|
||||
.map((entry) => normalizeIrcAllowEntry(entry))
|
||||
.map((entry) => entry.trim())
|
||||
.filter(Boolean),
|
||||
}),
|
||||
getExistingAllowFrom: ({ cfg }) => cfg.channels?.irc?.allowFrom ?? [],
|
||||
applyAllowFrom: ({ cfg, allowFrom }) => setIrcAllowFrom(cfg, allowFrom),
|
||||
});
|
||||
}
|
||||
const promptIrcAllowFrom = createPromptParsedAllowFromForAccount<CoreConfig>({
|
||||
defaultAccountId: (cfg) => resolveDefaultIrcAccountId(cfg),
|
||||
noteTitle: "IRC allowlist",
|
||||
noteLines: [
|
||||
"Allowlist IRC DMs by sender.",
|
||||
"Examples:",
|
||||
"- alice",
|
||||
"- alice!ident@example.org",
|
||||
"Multiple entries: comma-separated.",
|
||||
],
|
||||
message: "IRC allowFrom (nick or nick!user@host)",
|
||||
placeholder: "alice, bob!ident@example.org",
|
||||
parseEntries: (raw) => ({
|
||||
entries: parseListInput(raw)
|
||||
.map((entry) => normalizeIrcAllowEntry(entry))
|
||||
.map((entry) => entry.trim())
|
||||
.filter(Boolean),
|
||||
}),
|
||||
getExistingAllowFrom: ({ cfg }) => cfg.channels?.irc?.allowFrom ?? [],
|
||||
applyAllowFrom: ({ cfg, allowFrom }) => setIrcAllowFrom(cfg, allowFrom),
|
||||
});
|
||||
|
||||
async function promptIrcNickServConfig(params: {
|
||||
cfg: CoreConfig;
|
||||
|
||||
@@ -2,26 +2,21 @@ import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/channel-setup";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime";
|
||||
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/routing";
|
||||
import {
|
||||
createTopLevelChannelAllowFromSetter,
|
||||
createTopLevelChannelParsedAllowFromPrompt,
|
||||
createTopLevelChannelDmPolicy,
|
||||
mergeAllowFromEntries,
|
||||
parseSetupEntriesWithParser,
|
||||
patchTopLevelChannelConfigSection,
|
||||
promptParsedAllowFromForAccount,
|
||||
splitSetupEntries,
|
||||
} from "openclaw/plugin-sdk/setup";
|
||||
import type { ChannelSetupDmPolicy } from "openclaw/plugin-sdk/setup";
|
||||
import type { ChannelSetupWizard } from "openclaw/plugin-sdk/setup";
|
||||
import { formatDocsLink } from "openclaw/plugin-sdk/setup";
|
||||
import type { WizardPrompter } from "openclaw/plugin-sdk/setup";
|
||||
import { DEFAULT_RELAYS } from "./default-relays.js";
|
||||
import { getPublicKeyFromPrivate, normalizePubkey } from "./nostr-bus.js";
|
||||
import { resolveNostrAccount } from "./types.js";
|
||||
|
||||
const channel = "nostr" as const;
|
||||
const setNostrAllowFrom = createTopLevelChannelAllowFromSetter({
|
||||
channel,
|
||||
});
|
||||
|
||||
const NOSTR_SETUP_HELP_LINES = [
|
||||
"Use a Nostr private key in nsec or 64-character hex format.",
|
||||
@@ -68,24 +63,16 @@ function parseNostrAllowFrom(raw: string): { entries: string[]; error?: string }
|
||||
});
|
||||
}
|
||||
|
||||
async function promptNostrAllowFrom(params: {
|
||||
cfg: OpenClawConfig;
|
||||
prompter: WizardPrompter;
|
||||
}): Promise<OpenClawConfig> {
|
||||
return await promptParsedAllowFromForAccount({
|
||||
cfg: params.cfg,
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
prompter: params.prompter,
|
||||
noteTitle: "Nostr allowlist",
|
||||
noteLines: NOSTR_ALLOW_FROM_HELP_LINES,
|
||||
message: "Nostr allowFrom",
|
||||
placeholder: "npub1..., 0123abcd...",
|
||||
parseEntries: parseNostrAllowFrom,
|
||||
getExistingAllowFrom: ({ cfg }) => cfg.channels?.nostr?.allowFrom ?? [],
|
||||
mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed),
|
||||
applyAllowFrom: ({ cfg, allowFrom }) => setNostrAllowFrom(cfg, allowFrom),
|
||||
});
|
||||
}
|
||||
const promptNostrAllowFrom = createTopLevelChannelParsedAllowFromPrompt({
|
||||
channel,
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
noteTitle: "Nostr allowlist",
|
||||
noteLines: NOSTR_ALLOW_FROM_HELP_LINES,
|
||||
message: "Nostr allowFrom",
|
||||
placeholder: "npub1..., 0123abcd...",
|
||||
parseEntries: parseNostrAllowFrom,
|
||||
mergeEntries: ({ existing, parsed }) => mergeAllowFromEntries(existing, parsed),
|
||||
});
|
||||
|
||||
const nostrDmPolicy: ChannelSetupDmPolicy = createTopLevelChannelDmPolicy({
|
||||
label: "Nostr",
|
||||
|
||||
@@ -12,6 +12,8 @@ import {
|
||||
createAccountScopedGroupAccessSection,
|
||||
createAllowFromSection,
|
||||
createLegacyCompatChannelDmPolicy,
|
||||
createNestedChannelParsedAllowFromPrompt,
|
||||
createPromptParsedAllowFromForAccount,
|
||||
createNestedChannelAllowFromSetter,
|
||||
createNestedChannelDmPolicy,
|
||||
createNestedChannelDmPolicySetter,
|
||||
@@ -19,6 +21,7 @@ import {
|
||||
createTopLevelChannelDmPolicy,
|
||||
createTopLevelChannelDmPolicySetter,
|
||||
createTopLevelChannelGroupPolicySetter,
|
||||
createTopLevelChannelParsedAllowFromPrompt,
|
||||
normalizeAllowFromEntries,
|
||||
noteChannelLookupFailure,
|
||||
noteChannelLookupSummary,
|
||||
@@ -659,6 +662,91 @@ describe("promptParsedAllowFromForAccount", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("createPromptParsedAllowFromForAccount", () => {
|
||||
it("supports computed default account ids and optional notes", async () => {
|
||||
const promptAllowFrom = createPromptParsedAllowFromForAccount<OpenClawConfig>({
|
||||
defaultAccountId: () => "work",
|
||||
message: "msg",
|
||||
placeholder: "placeholder",
|
||||
parseEntries: (raw) => ({ entries: [raw.trim().toLowerCase()] }),
|
||||
getExistingAllowFrom: ({ cfg, accountId }) =>
|
||||
cfg.channels?.bluebubbles?.accounts?.[accountId]?.allowFrom ?? [],
|
||||
applyAllowFrom: ({ cfg, accountId, allowFrom }) =>
|
||||
patchChannelConfigForAccount({
|
||||
cfg,
|
||||
channel: "bluebubbles",
|
||||
accountId,
|
||||
patch: { allowFrom },
|
||||
}),
|
||||
});
|
||||
|
||||
const prompter = createPrompter(["Alice"]);
|
||||
const next = await promptAllowFrom({
|
||||
cfg: {
|
||||
channels: {
|
||||
bluebubbles: {
|
||||
accounts: {
|
||||
work: {
|
||||
allowFrom: ["old"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
prompter: prompter as any,
|
||||
});
|
||||
|
||||
expect(next.channels?.bluebubbles?.accounts?.work?.allowFrom).toEqual(["alice"]);
|
||||
expect(prompter.note).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("parsed allowFrom prompt builders", () => {
|
||||
it("builds a top-level parsed allowFrom prompt", async () => {
|
||||
const promptAllowFrom = createTopLevelChannelParsedAllowFromPrompt({
|
||||
channel: "nostr",
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
noteTitle: "Nostr allowlist",
|
||||
noteLines: ["line"],
|
||||
message: "msg",
|
||||
placeholder: "placeholder",
|
||||
parseEntries: (raw) => ({ entries: [raw.trim().toLowerCase()] }),
|
||||
});
|
||||
|
||||
const prompter = createPrompter(["npub1"]);
|
||||
const next = await promptAllowFrom({
|
||||
cfg: {},
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
prompter: prompter as any,
|
||||
});
|
||||
|
||||
expect(next.channels?.nostr?.allowFrom).toEqual(["npub1"]);
|
||||
expect(prompter.note).toHaveBeenCalledWith("line", "Nostr allowlist");
|
||||
});
|
||||
|
||||
it("builds a nested parsed allowFrom prompt", async () => {
|
||||
const promptAllowFrom = createNestedChannelParsedAllowFromPrompt({
|
||||
channel: "googlechat",
|
||||
section: "dm",
|
||||
defaultAccountId: DEFAULT_ACCOUNT_ID,
|
||||
enabled: true,
|
||||
message: "msg",
|
||||
placeholder: "placeholder",
|
||||
parseEntries: (raw) => ({ entries: [raw.trim()] }),
|
||||
});
|
||||
|
||||
const next = await promptAllowFrom({
|
||||
cfg: {},
|
||||
// oxlint-disable-next-line typescript/no-explicit-any
|
||||
prompter: createPrompter(["users/123"]) as any,
|
||||
});
|
||||
|
||||
expect(next.channels?.googlechat?.enabled).toBe(true);
|
||||
expect(next.channels?.googlechat?.dm?.allowFrom).toEqual(["users/123"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("channel lookup note helpers", () => {
|
||||
it("emits summary lines for resolved and unresolved entries", async () => {
|
||||
const prompter = { note: vi.fn(async () => undefined) };
|
||||
|
||||
@@ -1070,8 +1070,8 @@ export async function promptParsedAllowFromForAccount<TConfig extends OpenClawCo
|
||||
accountId?: string;
|
||||
defaultAccountId: string;
|
||||
prompter: Pick<WizardPrompter, "note" | "text">;
|
||||
noteTitle: string;
|
||||
noteLines: string[];
|
||||
noteTitle?: string;
|
||||
noteLines?: string[];
|
||||
message: string;
|
||||
placeholder: string;
|
||||
parseEntries: (raw: string) => ParsedAllowFromResult;
|
||||
@@ -1091,7 +1091,9 @@ export async function promptParsedAllowFromForAccount<TConfig extends OpenClawCo
|
||||
cfg: params.cfg,
|
||||
accountId,
|
||||
});
|
||||
await params.prompter.note(params.noteLines.join("\n"), params.noteTitle);
|
||||
if (params.noteTitle && params.noteLines && params.noteLines.length > 0) {
|
||||
await params.prompter.note(params.noteLines.join("\n"), params.noteTitle);
|
||||
}
|
||||
const entry = await params.prompter.text({
|
||||
message: params.message,
|
||||
placeholder: params.placeholder,
|
||||
@@ -1117,6 +1119,41 @@ export async function promptParsedAllowFromForAccount<TConfig extends OpenClawCo
|
||||
});
|
||||
}
|
||||
|
||||
export function createPromptParsedAllowFromForAccount<TConfig extends OpenClawConfig>(params: {
|
||||
defaultAccountId: string | ((cfg: TConfig) => string);
|
||||
noteTitle?: string;
|
||||
noteLines?: string[];
|
||||
message: string;
|
||||
placeholder: string;
|
||||
parseEntries: (raw: string) => ParsedAllowFromResult;
|
||||
getExistingAllowFrom: (params: { cfg: TConfig; accountId: string }) => Array<string | number>;
|
||||
mergeEntries?: (params: { existing: Array<string | number>; parsed: string[] }) => string[];
|
||||
applyAllowFrom: (params: {
|
||||
cfg: TConfig;
|
||||
accountId: string;
|
||||
allowFrom: string[];
|
||||
}) => TConfig | Promise<TConfig>;
|
||||
}): NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]> {
|
||||
return async ({ cfg, prompter, accountId }) =>
|
||||
await promptParsedAllowFromForAccount({
|
||||
cfg: cfg as TConfig,
|
||||
accountId,
|
||||
defaultAccountId:
|
||||
typeof params.defaultAccountId === "function"
|
||||
? params.defaultAccountId(cfg as TConfig)
|
||||
: params.defaultAccountId,
|
||||
prompter,
|
||||
...(params.noteTitle ? { noteTitle: params.noteTitle } : {}),
|
||||
...(params.noteLines ? { noteLines: params.noteLines } : {}),
|
||||
message: params.message,
|
||||
placeholder: params.placeholder,
|
||||
parseEntries: params.parseEntries,
|
||||
getExistingAllowFrom: params.getExistingAllowFrom,
|
||||
...(params.mergeEntries ? { mergeEntries: params.mergeEntries } : {}),
|
||||
applyAllowFrom: params.applyAllowFrom,
|
||||
});
|
||||
}
|
||||
|
||||
export async function promptParsedAllowFromForScopedChannel(params: {
|
||||
cfg: OpenClawConfig;
|
||||
channel: "imessage" | "signal";
|
||||
@@ -1154,6 +1191,75 @@ export async function promptParsedAllowFromForScopedChannel(params: {
|
||||
});
|
||||
}
|
||||
|
||||
export function createTopLevelChannelParsedAllowFromPrompt(params: {
|
||||
channel: string;
|
||||
defaultAccountId: string;
|
||||
enabled?: boolean;
|
||||
noteTitle?: string;
|
||||
noteLines?: string[];
|
||||
message: string;
|
||||
placeholder: string;
|
||||
parseEntries: (raw: string) => ParsedAllowFromResult;
|
||||
getExistingAllowFrom?: (cfg: OpenClawConfig) => Array<string | number>;
|
||||
mergeEntries?: (params: { existing: Array<string | number>; parsed: string[] }) => string[];
|
||||
}): NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]> {
|
||||
const setAllowFrom = createTopLevelChannelAllowFromSetter({
|
||||
channel: params.channel,
|
||||
...(params.enabled ? { enabled: true } : {}),
|
||||
});
|
||||
return createPromptParsedAllowFromForAccount({
|
||||
defaultAccountId: params.defaultAccountId,
|
||||
...(params.noteTitle ? { noteTitle: params.noteTitle } : {}),
|
||||
...(params.noteLines ? { noteLines: params.noteLines } : {}),
|
||||
message: params.message,
|
||||
placeholder: params.placeholder,
|
||||
parseEntries: params.parseEntries,
|
||||
getExistingAllowFrom: ({ cfg }) =>
|
||||
params.getExistingAllowFrom?.(cfg) ??
|
||||
(((cfg.channels?.[params.channel] as { allowFrom?: Array<string | number> } | undefined)
|
||||
?.allowFrom ??
|
||||
[]) as Array<string | number>),
|
||||
...(params.mergeEntries ? { mergeEntries: params.mergeEntries } : {}),
|
||||
applyAllowFrom: ({ cfg, allowFrom }) => setAllowFrom(cfg, allowFrom),
|
||||
});
|
||||
}
|
||||
|
||||
export function createNestedChannelParsedAllowFromPrompt(params: {
|
||||
channel: string;
|
||||
section: string;
|
||||
defaultAccountId: string;
|
||||
enabled?: boolean;
|
||||
noteTitle?: string;
|
||||
noteLines?: string[];
|
||||
message: string;
|
||||
placeholder: string;
|
||||
parseEntries: (raw: string) => ParsedAllowFromResult;
|
||||
getExistingAllowFrom?: (cfg: OpenClawConfig) => Array<string | number>;
|
||||
mergeEntries?: (params: { existing: Array<string | number>; parsed: string[] }) => string[];
|
||||
}): NonNullable<ChannelSetupDmPolicy["promptAllowFrom"]> {
|
||||
const setAllowFrom = createNestedChannelAllowFromSetter({
|
||||
channel: params.channel,
|
||||
section: params.section,
|
||||
...(params.enabled ? { enabled: true } : {}),
|
||||
});
|
||||
return createPromptParsedAllowFromForAccount({
|
||||
defaultAccountId: params.defaultAccountId,
|
||||
...(params.noteTitle ? { noteTitle: params.noteTitle } : {}),
|
||||
...(params.noteLines ? { noteLines: params.noteLines } : {}),
|
||||
message: params.message,
|
||||
placeholder: params.placeholder,
|
||||
parseEntries: params.parseEntries,
|
||||
getExistingAllowFrom: ({ cfg }) =>
|
||||
params.getExistingAllowFrom?.(cfg) ??
|
||||
(((cfg.channels?.[params.channel] as Record<string, unknown> | undefined)?.[
|
||||
params.section
|
||||
] as { allowFrom?: Array<string | number> } | undefined)?.allowFrom ??
|
||||
[]),
|
||||
...(params.mergeEntries ? { mergeEntries: params.mergeEntries } : {}),
|
||||
applyAllowFrom: ({ cfg, allowFrom }) => setAllowFrom(cfg, allowFrom),
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveParsedAllowFromEntries(params: {
|
||||
entries: string[];
|
||||
parseId: (raw: string) => string | null;
|
||||
|
||||
@@ -40,6 +40,8 @@ export {
|
||||
createAccountScopedGroupAccessSection,
|
||||
createAllowFromSection,
|
||||
createLegacyCompatChannelDmPolicy,
|
||||
createNestedChannelParsedAllowFromPrompt,
|
||||
createPromptParsedAllowFromForAccount,
|
||||
createNestedChannelAllowFromSetter,
|
||||
createNestedChannelDmPolicy,
|
||||
createNestedChannelDmPolicySetter,
|
||||
@@ -47,6 +49,7 @@ export {
|
||||
createTopLevelChannelDmPolicy,
|
||||
createTopLevelChannelDmPolicySetter,
|
||||
createTopLevelChannelGroupPolicySetter,
|
||||
createTopLevelChannelParsedAllowFromPrompt,
|
||||
mergeAllowFromEntries,
|
||||
normalizeAllowFromEntries,
|
||||
noteChannelLookupFailure,
|
||||
|
||||
Reference in New Issue
Block a user