mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-06 15:18:58 +00:00
fix(mattermost): collect setup URL in wizard
Fixes #76670.\n\nSummary:\n- Collect the Mattermost bot token and server URL as separate wizard patches so validation does not run before the URL is entered.\n- Preserve non-interactive Mattermost setup validation for explicit --bot-token + --http-url flows.\n- Add a regression test and changelog entry.\n\nVerification:\n- Reporter manually verified setup against a real Mattermost server.\n- pnpm test extensions/mattermost\n- pnpm tsgo:extensions\n- pnpm tsgo:extensions:test\n- pnpm exec oxfmt --check --threads=1 extensions/mattermost/src/setup-core.ts extensions/mattermost/src/setup-surface.ts extensions/mattermost/src/setup.test.ts\n- git diff --check upstream/main...HEAD
This commit is contained in:
@@ -116,6 +116,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
- Telegram/Codex: generate DM topic labels with Codex-compatible simple-completion requests so auto-created private topics can be renamed instead of staying `New Chat`.
|
||||
- Web fetch: bound guarded dispatcher cleanup after request timeouts so timed-out fetches return tool errors instead of leaving Gateway tool lanes active. (#78439) Thanks @obviyus.
|
||||
- Mattermost/setup: prompt for and persist the server base URL after the bot token in `openclaw setup --wizard`, instead of failing validation before `--http-url` is collected. Fixes #76670. Thanks @jacobtomlinson.
|
||||
- Gate Slack startup user allowlist resolution [AI]. (#77898) Thanks @pgondhi987.
|
||||
- OpenAI/Codex: suppress stale `openai-codex` GPT-5.1/5.2/5.3 model refs that ChatGPT/Codex OAuth accounts now reject, keeping model lists, config validation, and forward-compat resolution on current 5.4/5.5 routes. Fixes #67158. Thanks @drpau.
|
||||
- CLI/update: keep pnpm package updates on the running custom global install root and pass pnpm's `--global-dir` so `openclaw update` does not create a second default-prefix install when `OPENCLAW_HOME` or the shell points at a custom OpenClaw directory. Fixes #78377. Thanks @amknight.
|
||||
|
||||
@@ -30,6 +30,33 @@ export function resolveMattermostAccountWithSecrets(cfg: OpenClawConfig, account
|
||||
});
|
||||
}
|
||||
|
||||
export function applyMattermostSetupConfigPatch(params: {
|
||||
cfg: OpenClawConfig;
|
||||
accountId: string;
|
||||
name?: string;
|
||||
patch: Record<string, unknown>;
|
||||
}): OpenClawConfig {
|
||||
const namedConfig = applyAccountNameToChannelSection({
|
||||
cfg: params.cfg,
|
||||
channelKey: channel,
|
||||
accountId: params.accountId,
|
||||
name: params.name,
|
||||
});
|
||||
const next =
|
||||
params.accountId !== DEFAULT_ACCOUNT_ID
|
||||
? migrateBaseNameToDefaultAccount({
|
||||
cfg: namedConfig,
|
||||
channelKey: channel,
|
||||
})
|
||||
: namedConfig;
|
||||
return applySetupAccountConfigPatch({
|
||||
cfg: next,
|
||||
channelKey: channel,
|
||||
accountId: params.accountId,
|
||||
patch: params.patch,
|
||||
});
|
||||
}
|
||||
|
||||
export const mattermostSetupAdapter: ChannelSetupAdapter = {
|
||||
resolveAccountId: ({ accountId }) => normalizeAccountId(accountId),
|
||||
applyAccountName: ({ cfg, accountId, name }) =>
|
||||
@@ -66,23 +93,10 @@ export const mattermostSetupAdapter: ChannelSetupAdapter = {
|
||||
applyAccountConfig: ({ cfg, accountId, input }) => {
|
||||
const token = input.botToken ?? input.token;
|
||||
const baseUrl = normalizeMattermostBaseUrl(input.httpUrl);
|
||||
const namedConfig = applyAccountNameToChannelSection({
|
||||
return applyMattermostSetupConfigPatch({
|
||||
cfg,
|
||||
channelKey: channel,
|
||||
accountId,
|
||||
name: input.name,
|
||||
});
|
||||
const next =
|
||||
accountId !== DEFAULT_ACCOUNT_ID
|
||||
? migrateBaseNameToDefaultAccount({
|
||||
cfg: namedConfig,
|
||||
channelKey: channel,
|
||||
})
|
||||
: namedConfig;
|
||||
return applySetupAccountConfigPatch({
|
||||
cfg: next,
|
||||
channelKey: channel,
|
||||
accountId,
|
||||
patch: input.useEnv
|
||||
? {}
|
||||
: {
|
||||
|
||||
@@ -6,7 +6,11 @@ import {
|
||||
formatDocsLink,
|
||||
type ChannelSetupWizard,
|
||||
} from "openclaw/plugin-sdk/setup";
|
||||
import { isMattermostConfigured, resolveMattermostAccountWithSecrets } from "./setup-core.js";
|
||||
import {
|
||||
applyMattermostSetupConfigPatch,
|
||||
isMattermostConfigured,
|
||||
resolveMattermostAccountWithSecrets,
|
||||
} from "./setup-core.js";
|
||||
import { normalizeMattermostBaseUrl } from "./setup.client.runtime.js";
|
||||
import { hasConfiguredSecretInput } from "./setup.secret-input.runtime.js";
|
||||
|
||||
@@ -81,6 +85,12 @@ export const mattermostSetupWizard: ChannelSetupWizard = {
|
||||
hasConfiguredValue: hasConfiguredSecretInput(resolvedAccount.config.botToken),
|
||||
};
|
||||
},
|
||||
applySet: async ({ cfg, accountId, value }) =>
|
||||
applyMattermostSetupConfigPatch({
|
||||
cfg,
|
||||
accountId,
|
||||
patch: { botToken: value },
|
||||
}),
|
||||
},
|
||||
],
|
||||
textInputs: [
|
||||
@@ -106,6 +116,12 @@ export const mattermostSetupWizard: ChannelSetupWizard = {
|
||||
? undefined
|
||||
: "Mattermost base URL must include a valid base URL.",
|
||||
normalizeValue: ({ value }) => normalizeMattermostBaseUrl(value) ?? value.trim(),
|
||||
applySet: async ({ cfg, accountId, value }) =>
|
||||
applyMattermostSetupConfigPatch({
|
||||
cfg,
|
||||
accountId,
|
||||
patch: { baseUrl: value },
|
||||
}),
|
||||
},
|
||||
],
|
||||
disable: (cfg: OpenClawConfig) => ({
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api";
|
||||
import {
|
||||
createSetupWizardAdapter,
|
||||
createQueuedWizardPrompter,
|
||||
runSetupWizardConfigure,
|
||||
} from "openclaw/plugin-sdk/plugin-test-runtime";
|
||||
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig, OpenClawPluginApi } from "../runtime-api.js";
|
||||
@@ -352,6 +357,41 @@ describe("mattermost setup", () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("prompts for bot token and server URL before validating wizard setup", async () => {
|
||||
normalizeMattermostBaseUrl.mockImplementation((value: string | undefined) =>
|
||||
value?.startsWith("http") ? value : undefined,
|
||||
);
|
||||
const queued = createQueuedWizardPrompter({
|
||||
textValues: ["bot-token", "https://chat.example.com"],
|
||||
});
|
||||
const adapter = createSetupWizardAdapter({
|
||||
plugin: {
|
||||
id: "mattermost",
|
||||
meta: { label: "Mattermost" },
|
||||
config: {
|
||||
listAccountIds: () => [DEFAULT_ACCOUNT_ID],
|
||||
},
|
||||
setup: mattermostSetupAdapter,
|
||||
} as never,
|
||||
wizard: mattermostSetupWizard,
|
||||
});
|
||||
|
||||
const result = await runSetupWizardConfigure({
|
||||
configure: adapter.configure,
|
||||
cfg: { channels: { mattermost: {} } } as OpenClawConfig,
|
||||
prompter: queued.prompter,
|
||||
options: { secretInputMode: "plaintext" as const },
|
||||
});
|
||||
|
||||
const textMessages = queued.text.mock.calls.map(
|
||||
([params]) => (params as { message: string }).message,
|
||||
);
|
||||
expect(textMessages).toEqual(["Enter Mattermost bot token", "Enter Mattermost base URL"]);
|
||||
expect(result.cfg.channels?.mattermost?.botToken).toBe("bot-token");
|
||||
expect(result.cfg.channels?.mattermost?.baseUrl).toBe("https://chat.example.com");
|
||||
expect(result.accountId).toBe(DEFAULT_ACCOUNT_ID);
|
||||
});
|
||||
});
|
||||
|
||||
function registerEnvDefaults() {
|
||||
|
||||
Reference in New Issue
Block a user