mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 12:10:23 +00:00
Matrix: prompt invite auto-join during onboarding (#62168)
Merged via squash.
Prepared head SHA: aec7a2249a
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
committed by
GitHub
parent
8d2ccd851c
commit
9fd47a5aed
@@ -103,6 +103,44 @@ describe("updateMatrixAccountConfig", () => {
|
||||
expect(updated.channels?.["matrix"]?.accounts?.default?.proxy).toBeUndefined();
|
||||
});
|
||||
|
||||
it("stores and clears Matrix invite auto-join settings", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
matrix: {
|
||||
accounts: {
|
||||
default: {
|
||||
autoJoin: "allowlist",
|
||||
autoJoinAllowlist: ["#ops:example.org"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as CoreConfig;
|
||||
|
||||
const allowlistUpdated = updateMatrixAccountConfig(cfg, "default", {
|
||||
autoJoin: "allowlist",
|
||||
autoJoinAllowlist: ["!ops-room:example.org", "#ops:example.org"],
|
||||
});
|
||||
expect(allowlistUpdated.channels?.matrix?.accounts?.default).toMatchObject({
|
||||
autoJoin: "allowlist",
|
||||
autoJoinAllowlist: ["!ops-room:example.org", "#ops:example.org"],
|
||||
});
|
||||
|
||||
const offUpdated = updateMatrixAccountConfig(cfg, "default", {
|
||||
autoJoin: "off",
|
||||
autoJoinAllowlist: null,
|
||||
});
|
||||
expect(offUpdated.channels?.matrix?.accounts?.default?.autoJoin).toBe("off");
|
||||
expect(offUpdated.channels?.matrix?.accounts?.default?.autoJoinAllowlist).toBeUndefined();
|
||||
|
||||
const alwaysUpdated = updateMatrixAccountConfig(cfg, "default", {
|
||||
autoJoin: "always",
|
||||
autoJoinAllowlist: null,
|
||||
});
|
||||
expect(alwaysUpdated.channels?.matrix?.accounts?.default?.autoJoin).toBe("always");
|
||||
expect(alwaysUpdated.channels?.matrix?.accounts?.default?.autoJoinAllowlist).toBeUndefined();
|
||||
});
|
||||
|
||||
it("normalizes account id and defaults account enabled=true", () => {
|
||||
const updated = updateMatrixAccountConfig({} as CoreConfig, "Main Bot", {
|
||||
name: "Main Bot",
|
||||
|
||||
@@ -30,6 +30,8 @@ export type MatrixAccountPatch = {
|
||||
encryption?: boolean | null;
|
||||
initialSyncLimit?: number | null;
|
||||
allowBots?: MatrixConfig["allowBots"] | null;
|
||||
autoJoin?: MatrixConfig["autoJoin"] | null;
|
||||
autoJoinAllowlist?: MatrixConfig["autoJoinAllowlist"] | null;
|
||||
dm?: MatrixConfig["dm"] | null;
|
||||
groupPolicy?: MatrixConfig["groupPolicy"] | null;
|
||||
groupAllowFrom?: MatrixConfig["groupAllowFrom"] | null;
|
||||
@@ -203,6 +205,14 @@ export function updateMatrixAccountConfig(
|
||||
nextAccount.allowBots = patch.allowBots;
|
||||
}
|
||||
}
|
||||
if (patch.autoJoin !== undefined) {
|
||||
if (patch.autoJoin === null) {
|
||||
delete nextAccount.autoJoin;
|
||||
} else {
|
||||
nextAccount.autoJoin = patch.autoJoin;
|
||||
}
|
||||
}
|
||||
applyNullableArrayField(nextAccount, "autoJoinAllowlist", patch.autoJoinAllowlist);
|
||||
if (patch.dm !== undefined) {
|
||||
if (patch.dm === null) {
|
||||
delete nextAccount.dm;
|
||||
@@ -245,16 +255,20 @@ export function updateMatrixAccountConfig(
|
||||
);
|
||||
|
||||
if (shouldStoreMatrixAccountAtTopLevel(cfg, normalizedAccountId)) {
|
||||
const { accounts: _ignoredAccounts, defaultAccount, ...baseMatrix } = matrix;
|
||||
const { accounts: _ignoredAccounts, defaultAccount } = matrix;
|
||||
const {
|
||||
accounts: _ignoredNextAccounts,
|
||||
defaultAccount: _ignoredNextDefaultAccount,
|
||||
...topLevelAccount
|
||||
} = nextAccount;
|
||||
return {
|
||||
...cfg,
|
||||
channels: {
|
||||
...cfg.channels,
|
||||
matrix: {
|
||||
...baseMatrix,
|
||||
...(defaultAccount ? { defaultAccount } : {}),
|
||||
enabled: true,
|
||||
...nextAccount,
|
||||
...topLevelAccount,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -117,13 +117,18 @@ export async function runMatrixAddAccountAllowlistConfigure(params: {
|
||||
cfg: CoreConfig;
|
||||
allowFromInput: string;
|
||||
roomsAllowlistInput: string;
|
||||
autoJoinPolicy?: "always" | "allowlist" | "off";
|
||||
autoJoinAllowlistInput?: string;
|
||||
deviceName?: string;
|
||||
notes?: string[];
|
||||
}) {
|
||||
const prompter = createMatrixWizardPrompter({
|
||||
notes: params.notes,
|
||||
select: {
|
||||
"Matrix already configured. What do you want to do?": "add-account",
|
||||
"Matrix auth method": "token",
|
||||
"Matrix rooms access": "allowlist",
|
||||
"Matrix invite auto-join": params.autoJoinPolicy ?? "allowlist",
|
||||
},
|
||||
text: {
|
||||
"Matrix account name": "ops",
|
||||
@@ -132,10 +137,13 @@ export async function runMatrixAddAccountAllowlistConfigure(params: {
|
||||
"Matrix device name (optional)": params.deviceName ?? "",
|
||||
"Matrix allowFrom (full @user:server; display name only if unique)": params.allowFromInput,
|
||||
"Matrix rooms allowlist (comma-separated)": params.roomsAllowlistInput,
|
||||
"Matrix invite auto-join allowlist (comma-separated)":
|
||||
params.autoJoinAllowlistInput ?? "#ops-invites:example.org",
|
||||
},
|
||||
confirm: {
|
||||
"Enable end-to-end encryption (E2EE)?": false,
|
||||
"Configure Matrix rooms access?": true,
|
||||
"Configure Matrix invite auto-join?": true,
|
||||
},
|
||||
onConfirm: async () => false,
|
||||
});
|
||||
|
||||
@@ -85,6 +85,72 @@ describe("matrix onboarding", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("routes env-shortcut add-account flow through Matrix invite auto-join setup", async () => {
|
||||
installMatrixTestRuntime();
|
||||
|
||||
process.env.MATRIX_HOMESERVER = "https://matrix.env.example.org";
|
||||
process.env.MATRIX_USER_ID = "@env:example.org";
|
||||
process.env.MATRIX_PASSWORD = "env-password"; // pragma: allowlist secret
|
||||
process.env.MATRIX_ACCESS_TOKEN = "";
|
||||
process.env.MATRIX_OPS_HOMESERVER = "https://matrix.ops.env.example.org";
|
||||
process.env.MATRIX_OPS_ACCESS_TOKEN = "ops-env-token";
|
||||
|
||||
const notes: string[] = [];
|
||||
const prompter = createMatrixWizardPrompter({
|
||||
notes,
|
||||
select: {
|
||||
"Matrix already configured. What do you want to do?": "add-account",
|
||||
"Matrix rooms access": "allowlist",
|
||||
"Matrix invite auto-join": "allowlist",
|
||||
},
|
||||
text: {
|
||||
"Matrix account name": "ops",
|
||||
"Matrix rooms allowlist (comma-separated)": "!ops-room:example.org",
|
||||
"Matrix invite auto-join allowlist (comma-separated)": "#ops-invites:example.org",
|
||||
},
|
||||
confirm: {
|
||||
"Configure Matrix rooms access?": true,
|
||||
"Configure Matrix invite auto-join?": true,
|
||||
},
|
||||
onConfirm: (message) => message.startsWith("Matrix env vars detected"),
|
||||
});
|
||||
|
||||
const result = await runMatrixInteractiveConfigure({
|
||||
cfg: {
|
||||
channels: {
|
||||
matrix: {
|
||||
accounts: {
|
||||
default: {
|
||||
homeserver: "https://matrix.main.example.org",
|
||||
accessToken: "main-token",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as CoreConfig,
|
||||
prompter,
|
||||
shouldPromptAccountIds: true,
|
||||
configured: true,
|
||||
});
|
||||
|
||||
expect(result).not.toBe("skip");
|
||||
if (result === "skip") {
|
||||
return;
|
||||
}
|
||||
|
||||
expect(result.accountId).toBe("ops");
|
||||
expect(result.cfg.channels?.matrix?.accounts?.ops).toMatchObject({
|
||||
enabled: true,
|
||||
groupPolicy: "allowlist",
|
||||
groups: {
|
||||
"!ops-room:example.org": { enabled: true },
|
||||
},
|
||||
autoJoin: "allowlist",
|
||||
autoJoinAllowlist: ["#ops-invites:example.org"],
|
||||
});
|
||||
expect(notes.join("\n")).toContain("WARNING: Matrix invite auto-join defaults to off.");
|
||||
});
|
||||
|
||||
it("promotes legacy top-level Matrix config before adding a named account", async () => {
|
||||
installMatrixTestRuntime();
|
||||
|
||||
@@ -289,6 +355,7 @@ describe("matrix onboarding", () => {
|
||||
"Matrix credentials already configured. Keep them?": true,
|
||||
"Enable end-to-end encryption (E2EE)?": false,
|
||||
"Configure Matrix rooms access?": false,
|
||||
"Configure Matrix invite auto-join?": false,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -353,6 +420,7 @@ describe("matrix onboarding", () => {
|
||||
|
||||
it("writes allowlists and room access to the selected Matrix account", async () => {
|
||||
installMatrixTestRuntime();
|
||||
const notes: string[] = [];
|
||||
|
||||
const result = await runMatrixAddAccountAllowlistConfigure({
|
||||
cfg: {
|
||||
@@ -369,7 +437,9 @@ describe("matrix onboarding", () => {
|
||||
} as CoreConfig,
|
||||
allowFromInput: "@alice:example.org",
|
||||
roomsAllowlistInput: "!ops-room:example.org",
|
||||
autoJoinAllowlistInput: "#ops-invites:example.org",
|
||||
deviceName: "Ops Gateway",
|
||||
notes,
|
||||
});
|
||||
|
||||
expect(result).not.toBe("skip");
|
||||
@@ -387,12 +457,124 @@ describe("matrix onboarding", () => {
|
||||
allowFrom: ["@alice:example.org"],
|
||||
},
|
||||
groupPolicy: "allowlist",
|
||||
autoJoin: "allowlist",
|
||||
autoJoinAllowlist: ["#ops-invites:example.org"],
|
||||
groups: {
|
||||
"!ops-room:example.org": { enabled: true },
|
||||
},
|
||||
});
|
||||
expect(result.cfg.channels?.["matrix"]?.dm).toBeUndefined();
|
||||
expect(result.cfg.channels?.["matrix"]?.groups).toBeUndefined();
|
||||
expect(notes.join("\n")).toContain("WARNING: Matrix invite auto-join defaults to off.");
|
||||
});
|
||||
|
||||
it("clears Matrix invite auto-join allowlists when switching auto-join off", async () => {
|
||||
installMatrixTestRuntime();
|
||||
const notes: string[] = [];
|
||||
|
||||
const prompter = createMatrixWizardPrompter({
|
||||
notes,
|
||||
select: {
|
||||
"Matrix already configured. What do you want to do?": "update",
|
||||
"Matrix invite auto-join": "off",
|
||||
},
|
||||
text: {
|
||||
"Matrix homeserver URL": "https://matrix.example.org",
|
||||
"Matrix device name (optional)": "OpenClaw Gateway",
|
||||
},
|
||||
confirm: {
|
||||
"Matrix credentials already configured. Keep them?": true,
|
||||
"Enable end-to-end encryption (E2EE)?": false,
|
||||
"Configure Matrix rooms access?": false,
|
||||
"Configure Matrix invite auto-join?": true,
|
||||
"Update Matrix invite auto-join?": true,
|
||||
},
|
||||
});
|
||||
|
||||
const result = await runMatrixInteractiveConfigure({
|
||||
cfg: {
|
||||
channels: {
|
||||
matrix: {
|
||||
homeserver: "https://matrix.example.org",
|
||||
accessToken: "matrix-token",
|
||||
autoJoin: "allowlist",
|
||||
autoJoinAllowlist: ["#ops:example.org"],
|
||||
},
|
||||
},
|
||||
} as CoreConfig,
|
||||
prompter,
|
||||
configured: true,
|
||||
});
|
||||
|
||||
expect(result).not.toBe("skip");
|
||||
if (result === "skip") {
|
||||
return;
|
||||
}
|
||||
|
||||
expect(result.cfg.channels?.matrix?.autoJoin).toBe("off");
|
||||
expect(result.cfg.channels?.matrix?.autoJoinAllowlist).toBeUndefined();
|
||||
expect(notes.join("\n")).toContain("Matrix invite auto-join remains off.");
|
||||
expect(notes.join("\n")).toContain(
|
||||
"Agents will not join invited rooms or fresh DM-style invites until you change autoJoin.",
|
||||
);
|
||||
});
|
||||
|
||||
it("re-prompts Matrix invite auto-join allowlists until entries are stable invite targets", async () => {
|
||||
installMatrixTestRuntime();
|
||||
const notes: string[] = [];
|
||||
let inviteAllowlistPrompts = 0;
|
||||
|
||||
const prompter = createMatrixWizardPrompter({
|
||||
notes,
|
||||
select: {
|
||||
"Matrix already configured. What do you want to do?": "update",
|
||||
"Matrix invite auto-join": "allowlist",
|
||||
},
|
||||
text: {
|
||||
"Matrix homeserver URL": "https://matrix.example.org",
|
||||
"Matrix device name (optional)": "OpenClaw Gateway",
|
||||
},
|
||||
confirm: {
|
||||
"Matrix credentials already configured. Keep them?": true,
|
||||
"Enable end-to-end encryption (E2EE)?": false,
|
||||
"Configure Matrix rooms access?": false,
|
||||
"Configure Matrix invite auto-join?": true,
|
||||
"Update Matrix invite auto-join?": true,
|
||||
},
|
||||
onText: async (message) => {
|
||||
if (message === "Matrix invite auto-join allowlist (comma-separated)") {
|
||||
inviteAllowlistPrompts += 1;
|
||||
return inviteAllowlistPrompts === 1 ? "Project Room" : "#ops:example.org";
|
||||
}
|
||||
throw new Error(`unexpected text prompt: ${message}`);
|
||||
},
|
||||
});
|
||||
|
||||
const result = await runMatrixInteractiveConfigure({
|
||||
cfg: {
|
||||
channels: {
|
||||
matrix: {
|
||||
homeserver: "https://matrix.example.org",
|
||||
accessToken: "matrix-token",
|
||||
},
|
||||
},
|
||||
} as CoreConfig,
|
||||
prompter,
|
||||
configured: true,
|
||||
});
|
||||
|
||||
expect(result).not.toBe("skip");
|
||||
if (result === "skip") {
|
||||
return;
|
||||
}
|
||||
|
||||
expect(inviteAllowlistPrompts).toBe(2);
|
||||
expect(result.cfg.channels?.matrix?.autoJoin).toBe("allowlist");
|
||||
expect(result.cfg.channels?.matrix?.autoJoinAllowlist).toEqual(["#ops:example.org"]);
|
||||
expect(notes.join("\n")).toContain(
|
||||
"Use only stable Matrix invite targets for auto-join: !roomId:server, #alias:server, or *.",
|
||||
);
|
||||
expect(notes.join("\n")).toContain("Invalid: Project Room");
|
||||
});
|
||||
|
||||
it("reports account-scoped DM config keys for named accounts", () => {
|
||||
|
||||
@@ -30,13 +30,40 @@ import {
|
||||
normalizeAccountId,
|
||||
promptAccountId,
|
||||
promptChannelAccessConfig,
|
||||
splitSetupEntries,
|
||||
type RuntimeEnv,
|
||||
type WizardPrompter,
|
||||
} from "./runtime-api.js";
|
||||
import { moveSingleMatrixAccountConfigToNamedAccount } from "./setup-config.js";
|
||||
import type { CoreConfig } from "./types.js";
|
||||
import type { CoreConfig, MatrixConfig } from "./types.js";
|
||||
|
||||
const channel = "matrix" as const;
|
||||
type MatrixInviteAutoJoinPolicy = NonNullable<MatrixConfig["autoJoin"]>;
|
||||
|
||||
const matrixInviteAutoJoinOptions: Array<{
|
||||
value: MatrixInviteAutoJoinPolicy;
|
||||
label: string;
|
||||
}> = [
|
||||
{ value: "allowlist", label: "Allowlist (recommended)" },
|
||||
{ value: "always", label: "Always (join every invite)" },
|
||||
{ value: "off", label: "Off (do not auto-join invites)" },
|
||||
];
|
||||
|
||||
function isMatrixInviteAutoJoinPolicy(value: string): value is MatrixInviteAutoJoinPolicy {
|
||||
return value === "allowlist" || value === "always" || value === "off";
|
||||
}
|
||||
|
||||
function isMatrixInviteAutoJoinTarget(entry: string): boolean {
|
||||
return (
|
||||
entry === "*" ||
|
||||
(entry.startsWith("!") && entry.includes(":")) ||
|
||||
(entry.startsWith("#") && entry.includes(":"))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeMatrixInviteAutoJoinTargets(entries: string[]): string[] {
|
||||
return [...new Set(entries.map((entry) => entry.trim()).filter(Boolean))];
|
||||
}
|
||||
|
||||
function resolveMatrixOnboardingAccountId(cfg: CoreConfig, accountId?: string): string {
|
||||
return normalizeAccountId(
|
||||
@@ -95,12 +122,6 @@ async function promptMatrixAllowFrom(params: {
|
||||
const account = resolveMatrixAccount({ cfg, accountId });
|
||||
const canResolve = Boolean(account.configured);
|
||||
|
||||
const parseInput = (raw: string) =>
|
||||
raw
|
||||
.split(/[\n,;]+/g)
|
||||
.map((entry) => entry.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const isFullUserId = (value: string) => value.startsWith("@") && value.includes(":");
|
||||
|
||||
while (true) {
|
||||
@@ -110,7 +131,7 @@ async function promptMatrixAllowFrom(params: {
|
||||
initialValue: existingAllowFrom[0] ? String(existingAllowFrom[0]) : undefined,
|
||||
validate: (value) => (String(value ?? "").trim() ? undefined : "Required"),
|
||||
});
|
||||
const parts = parseInput(String(entry));
|
||||
const parts = splitSetupEntries(String(entry));
|
||||
const resolvedIds: string[] = [];
|
||||
const pending: string[] = [];
|
||||
const unresolved: string[] = [];
|
||||
@@ -187,6 +208,200 @@ function setMatrixGroupRooms(cfg: CoreConfig, roomKeys: string[], accountId?: st
|
||||
});
|
||||
}
|
||||
|
||||
function setMatrixAutoJoin(
|
||||
cfg: CoreConfig,
|
||||
autoJoin: MatrixInviteAutoJoinPolicy,
|
||||
autoJoinAllowlist: string[],
|
||||
accountId?: string,
|
||||
) {
|
||||
return updateMatrixAccountConfig(cfg, resolveMatrixOnboardingAccountId(cfg, accountId), {
|
||||
autoJoin,
|
||||
autoJoinAllowlist: autoJoin === "allowlist" ? autoJoinAllowlist : null,
|
||||
});
|
||||
}
|
||||
|
||||
async function configureMatrixInviteAutoJoin(params: {
|
||||
cfg: CoreConfig;
|
||||
prompter: WizardPrompter;
|
||||
accountId?: string;
|
||||
}): Promise<CoreConfig> {
|
||||
const accountId = resolveMatrixOnboardingAccountId(params.cfg, params.accountId);
|
||||
const existingConfig = resolveMatrixAccountConfig({ cfg: params.cfg, accountId });
|
||||
const currentPolicy = existingConfig.autoJoin ?? "off";
|
||||
const currentAllowlist = (existingConfig.autoJoinAllowlist ?? []).map((entry) => String(entry));
|
||||
const hasExistingConfig = existingConfig.autoJoin !== undefined || currentAllowlist.length > 0;
|
||||
|
||||
await params.prompter.note(
|
||||
[
|
||||
"WARNING: Matrix invite auto-join defaults to off.",
|
||||
"OpenClaw agents will not join invited rooms or fresh DM-style invites unless you set autoJoin.",
|
||||
'Choose "allowlist" to restrict joins or "always" to join every invite.',
|
||||
].join("\n"),
|
||||
"Matrix invite auto-join",
|
||||
);
|
||||
|
||||
const wants = await params.prompter.confirm({
|
||||
message: hasExistingConfig
|
||||
? "Update Matrix invite auto-join?"
|
||||
: "Configure Matrix invite auto-join?",
|
||||
initialValue: hasExistingConfig ? currentPolicy !== "off" : true,
|
||||
});
|
||||
if (!wants) {
|
||||
return params.cfg;
|
||||
}
|
||||
|
||||
const selectedPolicy = await params.prompter.select({
|
||||
message: "Matrix invite auto-join",
|
||||
options: matrixInviteAutoJoinOptions,
|
||||
initialValue: currentPolicy,
|
||||
});
|
||||
if (!isMatrixInviteAutoJoinPolicy(selectedPolicy)) {
|
||||
throw new Error(`Unsupported Matrix invite auto-join policy: ${String(selectedPolicy)}`);
|
||||
}
|
||||
const policy = selectedPolicy;
|
||||
|
||||
if (policy === "off") {
|
||||
await params.prompter.note(
|
||||
[
|
||||
"Matrix invite auto-join remains off.",
|
||||
"Agents will not join invited rooms or fresh DM-style invites until you change autoJoin.",
|
||||
].join("\n"),
|
||||
"Matrix invite auto-join",
|
||||
);
|
||||
return setMatrixAutoJoin(params.cfg, policy, [], accountId);
|
||||
}
|
||||
|
||||
if (policy === "always") {
|
||||
return setMatrixAutoJoin(params.cfg, policy, [], accountId);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const rawAllowlist = String(
|
||||
await params.prompter.text({
|
||||
message: "Matrix invite auto-join allowlist (comma-separated)",
|
||||
placeholder: "!roomId:server, #alias:server, *",
|
||||
initialValue: currentAllowlist[0] ? currentAllowlist.join(", ") : undefined,
|
||||
validate: (value) => {
|
||||
const entries = splitSetupEntries(String(value ?? ""));
|
||||
return entries.length > 0 ? undefined : "Required";
|
||||
},
|
||||
}),
|
||||
);
|
||||
const allowlist = normalizeMatrixInviteAutoJoinTargets(splitSetupEntries(rawAllowlist));
|
||||
const invalidEntries = allowlist.filter((entry) => !isMatrixInviteAutoJoinTarget(entry));
|
||||
if (allowlist.length === 0 || invalidEntries.length > 0) {
|
||||
await params.prompter.note(
|
||||
[
|
||||
"Use only stable Matrix invite targets for auto-join: !roomId:server, #alias:server, or *.",
|
||||
invalidEntries.length > 0 ? `Invalid: ${invalidEntries.join(", ")}` : undefined,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
"Matrix invite auto-join",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
return setMatrixAutoJoin(params.cfg, "allowlist", allowlist, accountId);
|
||||
}
|
||||
}
|
||||
|
||||
async function configureMatrixAccessPrompts(params: {
|
||||
cfg: CoreConfig;
|
||||
prompter: WizardPrompter;
|
||||
forceAllowFrom: boolean;
|
||||
accountId: string;
|
||||
}): Promise<CoreConfig> {
|
||||
let next = params.cfg;
|
||||
|
||||
if (params.forceAllowFrom) {
|
||||
next = await promptMatrixAllowFrom({
|
||||
cfg: next,
|
||||
prompter: params.prompter,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
}
|
||||
|
||||
const existingAccountConfig = resolveMatrixAccountConfig({
|
||||
cfg: next,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
const existingGroups = existingAccountConfig.groups ?? existingAccountConfig.rooms;
|
||||
const accessConfig = await promptChannelAccessConfig({
|
||||
prompter: params.prompter,
|
||||
label: "Matrix rooms",
|
||||
currentPolicy: existingAccountConfig.groupPolicy ?? "allowlist",
|
||||
currentEntries: Object.keys(existingGroups ?? {}),
|
||||
placeholder: "!roomId:server, #alias:server, Project Room",
|
||||
updatePrompt: Boolean(existingGroups),
|
||||
});
|
||||
if (accessConfig) {
|
||||
if (accessConfig.policy !== "allowlist") {
|
||||
next = setMatrixGroupPolicy(next, accessConfig.policy, params.accountId);
|
||||
} else {
|
||||
let roomKeys = accessConfig.entries;
|
||||
if (accessConfig.entries.length > 0) {
|
||||
try {
|
||||
const resolvedIds: string[] = [];
|
||||
const unresolved: string[] = [];
|
||||
for (const entry of accessConfig.entries) {
|
||||
const trimmed = entry.trim();
|
||||
if (!trimmed) {
|
||||
continue;
|
||||
}
|
||||
const cleaned = trimmed.replace(/^(room|channel):/i, "").trim();
|
||||
if (cleaned.startsWith("!") && cleaned.includes(":")) {
|
||||
resolvedIds.push(cleaned);
|
||||
continue;
|
||||
}
|
||||
const matches = await listMatrixDirectoryGroupsLive({
|
||||
cfg: next,
|
||||
accountId: params.accountId,
|
||||
query: trimmed,
|
||||
limit: 10,
|
||||
});
|
||||
const exact = matches.find(
|
||||
(match) => (match.name ?? "").toLowerCase() === trimmed.toLowerCase(),
|
||||
);
|
||||
const best = exact ?? matches[0];
|
||||
if (best?.id) {
|
||||
resolvedIds.push(best.id);
|
||||
} else {
|
||||
unresolved.push(entry);
|
||||
}
|
||||
}
|
||||
roomKeys = [...resolvedIds, ...unresolved.map((entry) => entry.trim()).filter(Boolean)];
|
||||
if (resolvedIds.length > 0 || unresolved.length > 0) {
|
||||
await params.prompter.note(
|
||||
[
|
||||
resolvedIds.length > 0 ? `Resolved: ${resolvedIds.join(", ")}` : undefined,
|
||||
unresolved.length > 0
|
||||
? `Unresolved (kept as typed): ${unresolved.join(", ")}`
|
||||
: undefined,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
"Matrix rooms",
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
await params.prompter.note(
|
||||
`Room lookup failed; keeping entries as typed. ${String(err)}`,
|
||||
"Matrix rooms",
|
||||
);
|
||||
}
|
||||
}
|
||||
next = setMatrixGroupPolicy(next, "allowlist", params.accountId);
|
||||
next = setMatrixGroupRooms(next, roomKeys, params.accountId);
|
||||
}
|
||||
}
|
||||
|
||||
return await configureMatrixInviteAutoJoin({
|
||||
cfg: next,
|
||||
prompter: params.prompter,
|
||||
accountId: params.accountId,
|
||||
});
|
||||
}
|
||||
|
||||
const dmPolicy: ChannelSetupDmPolicy = {
|
||||
label: "Matrix",
|
||||
channel,
|
||||
@@ -289,13 +504,12 @@ async function runMatrixConfigure(params: {
|
||||
});
|
||||
if (useEnv) {
|
||||
next = updateMatrixAccountConfig(next, accountId, { enabled: true });
|
||||
if (params.forceAllowFrom) {
|
||||
next = await promptMatrixAllowFrom({
|
||||
cfg: next,
|
||||
prompter: params.prompter,
|
||||
accountId,
|
||||
});
|
||||
}
|
||||
next = await configureMatrixAccessPrompts({
|
||||
cfg: next,
|
||||
prompter: params.prompter,
|
||||
forceAllowFrom: params.forceAllowFrom,
|
||||
accountId,
|
||||
});
|
||||
return { cfg: next, accountId };
|
||||
}
|
||||
}
|
||||
@@ -421,84 +635,12 @@ async function runMatrixConfigure(params: {
|
||||
encryption: enableEncryption,
|
||||
});
|
||||
|
||||
if (params.forceAllowFrom) {
|
||||
next = await promptMatrixAllowFrom({
|
||||
cfg: next,
|
||||
prompter: params.prompter,
|
||||
accountId,
|
||||
});
|
||||
}
|
||||
|
||||
const existingAccountConfig = resolveMatrixAccountConfig({ cfg: next, accountId });
|
||||
const existingGroups = existingAccountConfig.groups ?? existingAccountConfig.rooms;
|
||||
const accessConfig = await promptChannelAccessConfig({
|
||||
next = await configureMatrixAccessPrompts({
|
||||
cfg: next,
|
||||
prompter: params.prompter,
|
||||
label: "Matrix rooms",
|
||||
currentPolicy: existingAccountConfig.groupPolicy ?? "allowlist",
|
||||
currentEntries: Object.keys(existingGroups ?? {}),
|
||||
placeholder: "!roomId:server, #alias:server, Project Room",
|
||||
updatePrompt: Boolean(existingGroups),
|
||||
forceAllowFrom: params.forceAllowFrom,
|
||||
accountId,
|
||||
});
|
||||
if (accessConfig) {
|
||||
if (accessConfig.policy !== "allowlist") {
|
||||
next = setMatrixGroupPolicy(next, accessConfig.policy, accountId);
|
||||
} else {
|
||||
let roomKeys = accessConfig.entries;
|
||||
if (accessConfig.entries.length > 0) {
|
||||
try {
|
||||
const resolvedIds: string[] = [];
|
||||
const unresolved: string[] = [];
|
||||
for (const entry of accessConfig.entries) {
|
||||
const trimmed = entry.trim();
|
||||
if (!trimmed) {
|
||||
continue;
|
||||
}
|
||||
const cleaned = trimmed.replace(/^(room|channel):/i, "").trim();
|
||||
if (cleaned.startsWith("!") && cleaned.includes(":")) {
|
||||
resolvedIds.push(cleaned);
|
||||
continue;
|
||||
}
|
||||
const matches = await listMatrixDirectoryGroupsLive({
|
||||
cfg: next,
|
||||
accountId,
|
||||
query: trimmed,
|
||||
limit: 10,
|
||||
});
|
||||
const exact = matches.find(
|
||||
(match) => (match.name ?? "").toLowerCase() === trimmed.toLowerCase(),
|
||||
);
|
||||
const best = exact ?? matches[0];
|
||||
if (best?.id) {
|
||||
resolvedIds.push(best.id);
|
||||
} else {
|
||||
unresolved.push(entry);
|
||||
}
|
||||
}
|
||||
roomKeys = [...resolvedIds, ...unresolved.map((entry) => entry.trim()).filter(Boolean)];
|
||||
if (resolvedIds.length > 0 || unresolved.length > 0) {
|
||||
await params.prompter.note(
|
||||
[
|
||||
resolvedIds.length > 0 ? `Resolved: ${resolvedIds.join(", ")}` : undefined,
|
||||
unresolved.length > 0
|
||||
? `Unresolved (kept as typed): ${unresolved.join(", ")}`
|
||||
: undefined,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
"Matrix rooms",
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
await params.prompter.note(
|
||||
`Room lookup failed; keeping entries as typed. ${String(err)}`,
|
||||
"Matrix rooms",
|
||||
);
|
||||
}
|
||||
}
|
||||
next = setMatrixGroupPolicy(next, "allowlist", accountId);
|
||||
next = setMatrixGroupRooms(next, roomKeys, accountId);
|
||||
}
|
||||
}
|
||||
|
||||
return { cfg: next, accountId };
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ export {
|
||||
moveSingleAccountChannelSectionToDefaultAccount,
|
||||
promptAccountId,
|
||||
promptChannelAccessConfig,
|
||||
splitSetupEntries,
|
||||
} from "openclaw/plugin-sdk/setup";
|
||||
export type { RuntimeEnv } from "openclaw/plugin-sdk/runtime";
|
||||
export {
|
||||
|
||||
Reference in New Issue
Block a user