@openclaw/mattermost 2026.7.1 → 2026.7.2-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,83 @@
1
+ import { f as normalizeMattermostBaseUrl } from "./client-BzLj4dyf.js";
2
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { resolveChannelPreviewStreamMode, resolveChannelStreamingBlockCoalesce, resolveChannelStreamingBlockEnabled, resolveChannelStreamingChunkMode } from "openclaw/plugin-sdk/channel-outbound";
4
+ import { createAccountListHelpers, hasConfiguredAccountValue } from "openclaw/plugin-sdk/account-helpers";
5
+ import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
6
+ import { resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-resolution";
7
+ import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString } from "openclaw/plugin-sdk/secret-input";
8
+ //#region extensions/mattermost/src/mattermost/accounts.ts
9
+ const mattermostAccountHelpers = createAccountListHelpers("mattermost", { hasImplicitDefaultAccount: (cfg) => {
10
+ const mattermost = cfg.channels?.mattermost;
11
+ return Boolean(mattermost?.baseUrl?.trim() && (hasConfiguredAccountValue(mattermost.botToken) || process.env.MATTERMOST_BOT_TOKEN?.trim()));
12
+ } });
13
+ function listMattermostAccountIds(cfg) {
14
+ return mattermostAccountHelpers.listAccountIds(cfg);
15
+ }
16
+ function resolveDefaultMattermostAccountId(cfg) {
17
+ return mattermostAccountHelpers.resolveDefaultAccountId(cfg);
18
+ }
19
+ function mergeMattermostAccountConfig(cfg, accountId) {
20
+ return resolveMergedAccountConfig({
21
+ channelConfig: cfg.channels?.mattermost,
22
+ accounts: cfg.channels?.mattermost?.accounts,
23
+ accountId,
24
+ omitKeys: ["defaultAccount"],
25
+ nestedObjectKeys: ["commands"]
26
+ });
27
+ }
28
+ function resolveMattermostRequireMention(config) {
29
+ if (config.chatmode === "oncall") return true;
30
+ if (config.chatmode === "onmessage") return false;
31
+ if (config.chatmode === "onchar") return true;
32
+ return config.requireMention;
33
+ }
34
+ function resolveMattermostAccount(params) {
35
+ const accountId = normalizeAccountId(params.accountId ?? resolveDefaultMattermostAccountId(params.cfg));
36
+ const baseEnabled = params.cfg.channels?.mattermost?.enabled !== false;
37
+ const merged = mergeMattermostAccountConfig(params.cfg, accountId);
38
+ const accountEnabled = merged.enabled !== false;
39
+ const enabled = baseEnabled && accountEnabled;
40
+ const allowEnv = accountId === DEFAULT_ACCOUNT_ID;
41
+ const envToken = allowEnv ? process.env.MATTERMOST_BOT_TOKEN?.trim() : void 0;
42
+ const envUrl = allowEnv ? process.env.MATTERMOST_URL?.trim() : void 0;
43
+ const configToken = params.allowUnresolvedSecretRef ? normalizeSecretInputString(merged.botToken) : normalizeResolvedSecretInputString({
44
+ value: merged.botToken,
45
+ path: `channels.mattermost.accounts.${accountId}.botToken`
46
+ });
47
+ const configUrl = merged.baseUrl?.trim();
48
+ const botToken = configToken || envToken;
49
+ const baseUrl = normalizeMattermostBaseUrl(configUrl || envUrl);
50
+ const requireMention = resolveMattermostRequireMention(merged);
51
+ const botTokenSource = configToken ? "config" : envToken ? "env" : "none";
52
+ const baseUrlSource = configUrl ? "config" : envUrl ? "env" : "none";
53
+ return {
54
+ accountId,
55
+ enabled,
56
+ name: normalizeOptionalString(merged.name),
57
+ botToken,
58
+ baseUrl,
59
+ botTokenSource,
60
+ baseUrlSource,
61
+ config: merged,
62
+ chatmode: merged.chatmode,
63
+ oncharPrefixes: merged.oncharPrefixes,
64
+ requireMention,
65
+ textChunkLimit: merged.textChunkLimit,
66
+ chunkMode: resolveChannelStreamingChunkMode(merged),
67
+ streamingMode: resolveChannelPreviewStreamMode(merged, "partial"),
68
+ blockStreaming: resolveChannelStreamingBlockEnabled(merged),
69
+ blockStreamingCoalesce: resolveChannelStreamingBlockCoalesce(merged)
70
+ };
71
+ }
72
+ /**
73
+ * Resolve the effective replyToMode for a given chat type.
74
+ * Direct messages stay flat unless explicitly opted into a per-chat-type mode.
75
+ */
76
+ function resolveMattermostReplyToMode(account, kind) {
77
+ const scopedMode = account.config.replyToModeByChatType?.[kind];
78
+ if (scopedMode !== void 0) return scopedMode;
79
+ if (kind === "direct") return "off";
80
+ return account.config.replyToMode ?? "off";
81
+ }
82
+ //#endregion
83
+ export { buildSecretInputSchema as a, resolveMattermostReplyToMode as i, resolveDefaultMattermostAccountId as n, hasConfiguredSecretInput as o, resolveMattermostAccount as r, listMattermostAccountIds as t };
package/dist/api.js CHANGED
@@ -1,2 +1,3 @@
1
- import { r as isMattermostSenderAllowed } from "./monitor-auth-BiDuyvOc.js";
2
- export { isMattermostSenderAllowed };
1
+ import { r as isMattermostSenderAllowed } from "./monitor-auth-dEHa1_On.js";
2
+ import { t as buildButtonAttachments } from "./interactions-DO7J-ND1.js";
3
+ export { buildButtonAttachments, isMattermostSenderAllowed };
@@ -1,5 +1,5 @@
1
- import { a as describeMattermostAccount, c as mattermostMeta, i as MattermostChannelConfigSchema, n as mattermostSetupWizard, o as isMattermostConfigured, r as mattermostSetupAdapter, s as mattermostConfigAdapter, t as mattermostPlugin } from "./channel-plugin-runtime-DhS8rwfs.js";
2
- import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-BIXLORHU.js";
1
+ import { a as MattermostChannelConfigSchema, c as mattermostConfigAdapter, l as mattermostMeta, n as mattermostSetupWizard, o as describeMattermostAccount, r as mattermostSetupAdapter, s as isMattermostConfigured, t as mattermostPlugin } from "./channel-plugin-runtime-BXmjNn6B.js";
2
+ import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-CL1PxV3z.js";
3
3
  //#region extensions/mattermost/src/channel.setup.ts
4
4
  const mattermostSetupPlugin = {
5
5
  id: "mattermost",
@@ -23,7 +23,7 @@ const mattermostSetupPlugin = {
23
23
  isConfigured: isMattermostConfigured,
24
24
  describeAccount: describeMattermostAccount
25
25
  },
26
- gateway: { resolveGatewayAuthBypassPaths: ({ cfg }) => resolveMattermostGatewayAuthBypassPaths(cfg) },
26
+ gateway: { resolveGatewayAuthBypassPaths: resolveMattermostGatewayAuthBypassPaths },
27
27
  setup: mattermostSetupAdapter,
28
28
  setupWizard: mattermostSetupWizard
29
29
  };
@@ -1,30 +1,31 @@
1
- import { C as hasConfiguredSecretInput, S as buildSecretInputSchema, g as normalizeMattermostBaseUrl, i as resolveMattermostReplyToMode, n as resolveDefaultMattermostAccountId, r as resolveMattermostAccount, t as listMattermostAccountIds } from "./accounts-ITTlduDO.js";
2
- import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-BIXLORHU.js";
3
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-ttH0DCuq.js";
4
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Cx0LUNXy.js";
1
+ import { f as normalizeMattermostBaseUrl } from "./client-BzLj4dyf.js";
2
+ import { a as buildSecretInputSchema, i as resolveMattermostReplyToMode, n as resolveDefaultMattermostAccountId, o as hasConfiguredSecretInput, r as resolveMattermostAccount, t as listMattermostAccountIds } from "./accounts-C4Azn6rA.js";
3
+ import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-CL1PxV3z.js";
4
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BaUvVh8e.js";
5
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-B4R5Bmhv.js";
5
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
7
+ import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
8
+ import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
9
+ import { z } from "zod";
6
10
  import { formatNormalizedAllowFromEntries } from "openclaw/plugin-sdk/allow-from";
7
11
  import { createLoggedPairingApprovalNotifier } from "openclaw/plugin-sdk/channel-pairing";
8
12
  import { createAccountStatusSink, createChannelMessageAdapterFromOutbound } from "openclaw/plugin-sdk/channel-outbound";
9
13
  import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, stripChannelTargetPrefix, stripTargetKindPrefix } from "openclaw/plugin-sdk/core";
10
- import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
11
- import { createDangerousNameMatchingMutableAllowlistWarningCollector, createRestrictSendersChannelSecurity, resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
14
+ import { createChannelConfigUiHints, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
15
+ import { buildChannelGroupsScopeTree, buildMutableAllowEntryDetector, collectStandardAllowlistLists, createDangerousNameMatchingMutableAllowlistWarningCollector, createRestrictSendersChannelSecurity, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
12
16
  import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
13
17
  import { createChannelDirectoryAdapter } from "openclaw/plugin-sdk/directory-runtime";
14
- import { buildPassiveProbedChannelStatusSummary } from "openclaw/plugin-sdk/extension-shared";
15
- import { normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveMessagePresentationControlValue } from "openclaw/plugin-sdk/interactive-runtime";
18
+ import { normalizeMessagePresentation, renderMessagePresentationFallbackText, resolveMessagePresentationButtonAction, resolveMessagePresentationControlValue } from "openclaw/plugin-sdk/interactive-runtime";
16
19
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
17
20
  import { resolvePayloadMediaUrls, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
18
- import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
19
21
  import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
20
22
  import { chunkTextForOutbound, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
21
- import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
23
+ import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
22
24
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
23
25
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
24
- import { z } from "zod";
25
26
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
26
- import { BlockStreamingCoalesceSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildChannelConfigSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-primitives";
27
- import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, createSetupTranslator, createStandardChannelSetupStatus, formatDocsLink, migrateBaseNameToDefaultAccount } from "openclaw/plugin-sdk/setup";
27
+ import { BlockStreamingCoalesceSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildChannelConfigSchema, buildGroupEntrySchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
28
+ import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, baseUrlTextInput, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, migrateBaseNameToDefaultAccount, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
28
29
  import { createSetupInputPresenceValidator } from "openclaw/plugin-sdk/setup-runtime";
29
30
  //#region extensions/mattermost/src/approval-auth.ts
30
31
  const MATTERMOST_USER_ID_RE = /^[a-z0-9]{26}$/;
@@ -32,20 +33,16 @@ function normalizeMattermostApproverId(value) {
32
33
  const lowered = normalizeLowercaseStringOrEmpty(String(value).trim().replace(/^(mattermost|user):/i, "").replace(/^@/, "").trim());
33
34
  return MATTERMOST_USER_ID_RE.test(lowered) ? lowered : void 0;
34
35
  }
35
- const mattermostApprovalAuth = createResolvedApproverActionAuthAdapter({
36
+ const mattermostApprovalAuth = createChannelApprovalAuth({
36
37
  channelLabel: "Mattermost",
37
- resolveApprovers: ({ cfg, accountId }) => {
38
- const account = resolveMattermostAccount({
38
+ resolveInputs: ({ cfg, accountId }) => {
39
+ return { allowFrom: resolveMattermostAccount({
39
40
  cfg,
40
41
  accountId
41
- }).config;
42
- return resolveApprovalApprovers({
43
- allowFrom: account.allowFrom,
44
- normalizeApprover: normalizeMattermostApproverId
45
- });
42
+ }).config.allowFrom };
46
43
  },
47
- normalizeSenderId: (value) => normalizeMattermostApproverId(value)
48
- });
44
+ normalizeApprover: normalizeMattermostApproverId
45
+ }).approvalAuth;
49
46
  //#endregion
50
47
  //#region extensions/mattermost/src/channel-config-shared.ts
51
48
  const mattermostMeta = {
@@ -103,9 +100,14 @@ function describeMattermostAccount(account) {
103
100
  }
104
101
  //#endregion
105
102
  //#region extensions/mattermost/src/config-schema-core.ts
106
- const MattermostGroupSchema = z.object({
107
- /** Whether mentions are required to trigger the bot in this group. */
108
- requireMention: z.boolean().optional() }).strict();
103
+ const MattermostGroupSchema = buildGroupEntrySchema().omit({
104
+ tools: true,
105
+ toolsBySender: true,
106
+ skills: true,
107
+ enabled: true,
108
+ allowFrom: true,
109
+ systemPrompt: true
110
+ });
109
111
  function requireMattermostOpenAllowFrom(params) {
110
112
  requireOpenAllowFrom({
111
113
  policy: params.policy,
@@ -155,25 +157,38 @@ const MattermostStreamingProgressSchema = z.object({
155
157
  labels: z.array(z.string()).optional(),
156
158
  maxLines: z.number().int().positive().optional(),
157
159
  maxLineChars: z.number().int().positive().optional(),
158
- toolProgress: z.boolean().optional()
160
+ toolProgress: z.boolean().optional(),
161
+ commandText: z.enum(["raw", "status"]).optional()
162
+ }).strict();
163
+ const MattermostStreamingPreviewSchema = z.object({
164
+ toolProgress: z.boolean().optional(),
165
+ commandText: z.enum(["raw", "status"]).optional()
159
166
  }).strict();
160
- const MattermostStreamingPreviewSchema = z.object({ toolProgress: z.boolean().optional() }).strict();
161
167
  const MattermostStreamingBlockSchema = z.object({
162
168
  enabled: z.boolean().optional(),
163
169
  coalesce: BlockStreamingCoalesceSchema.optional()
164
170
  }).strict();
165
- const MattermostStreamingSchema = z.union([
166
- MattermostStreamingModeSchema,
167
- z.boolean(),
168
- z.object({
169
- mode: MattermostStreamingModeSchema.optional(),
170
- chunkMode: z.enum(["length", "newline"]).optional(),
171
- preview: MattermostStreamingPreviewSchema.optional(),
172
- progress: MattermostStreamingProgressSchema.optional(),
173
- block: MattermostStreamingBlockSchema.optional()
174
- }).strict()
171
+ const MattermostStreamingSchema = z.object({
172
+ mode: MattermostStreamingModeSchema.optional(),
173
+ chunkMode: z.enum(["length", "newline"]).optional(),
174
+ preview: MattermostStreamingPreviewSchema.optional(),
175
+ progress: MattermostStreamingProgressSchema.optional(),
176
+ block: MattermostStreamingBlockSchema.optional()
177
+ }).strict();
178
+ const MattermostReplyToModeSchema = z.enum([
179
+ "off",
180
+ "first",
181
+ "all",
182
+ "batched"
175
183
  ]);
176
- const MattermostAccountSchemaBase = z.object({
184
+ const MattermostReplyToModeByChatTypeSchema = z.object({
185
+ direct: MattermostReplyToModeSchema.optional(),
186
+ group: MattermostReplyToModeSchema.optional(),
187
+ channel: MattermostReplyToModeSchema.optional()
188
+ }).strict();
189
+ //#endregion
190
+ //#region extensions/mattermost/src/config-surface.ts
191
+ const MattermostChannelConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(z.object({
177
192
  name: z.string().optional(),
178
193
  capabilities: z.array(z.string()).optional(),
179
194
  dangerouslyAllowNameMatching: z.boolean().optional(),
@@ -194,16 +209,9 @@ const MattermostAccountSchemaBase = z.object({
194
209
  groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(),
195
210
  groupPolicy: GroupPolicySchema.optional().default("allowlist"),
196
211
  textChunkLimit: z.number().int().positive().optional(),
197
- chunkMode: z.enum(["length", "newline"]).optional(),
198
212
  streaming: MattermostStreamingSchema.optional(),
199
- blockStreaming: z.boolean().optional(),
200
- blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(),
201
- replyToMode: z.enum([
202
- "off",
203
- "first",
204
- "all",
205
- "batched"
206
- ]).optional(),
213
+ replyToMode: MattermostReplyToModeSchema.optional(),
214
+ replyToModeByChatType: MattermostReplyToModeByChatTypeSchema.optional(),
207
215
  responsePrefix: z.string().optional(),
208
216
  actions: z.object({ reactions: z.boolean().optional() }).optional(),
209
217
  commands: MattermostSlashCommandsSchema,
@@ -217,34 +225,24 @@ const MattermostAccountSchemaBase = z.object({
217
225
  network: MattermostNetworkSchema,
218
226
  /** Retry configuration for DM channel creation */
219
227
  dmChannelRetry: DmChannelRetrySchema
220
- }).strict();
221
- const MattermostAccountSchema = MattermostAccountSchemaBase.superRefine((value, ctx) => {
222
- requireMattermostOpenAllowFrom({
223
- policy: value.dmPolicy,
224
- allowFrom: value.allowFrom,
225
- ctx
226
- });
227
- });
228
- //#endregion
229
- //#region extensions/mattermost/src/config-surface.ts
230
- const MattermostChannelConfigSchema = buildChannelConfigSchema(MattermostAccountSchemaBase.extend({
231
- accounts: z.record(z.string(), MattermostAccountSchema.optional()).optional(),
232
- defaultAccount: z.string().optional()
233
- }).superRefine((value, ctx) => {
234
- requireMattermostOpenAllowFrom({
235
- policy: value.dmPolicy,
236
- allowFrom: value.allowFrom,
237
- ctx
238
- });
228
+ }).strict(), {
229
+ optionalAccount: true,
230
+ refine: (value, ctx) => {
231
+ requireMattermostOpenAllowFrom({
232
+ policy: value.dmPolicy,
233
+ allowFrom: value.allowFrom,
234
+ ctx
235
+ });
236
+ }
239
237
  }), { uiHints: {
240
238
  "": {
241
239
  label: "Mattermost",
242
240
  help: "Mattermost channel provider configuration for bot auth, access policy, slash commands, and preview streaming."
243
241
  },
244
- dmPolicy: {
245
- label: "Mattermost DM Policy",
246
- help: "Direct message access control (\"pairing\" recommended). \"open\" requires channels.mattermost.allowFrom=[\"*\"]."
247
- },
242
+ ...createChannelConfigUiHints({
243
+ channelLabel: "Mattermost",
244
+ dmPolicy: { channelKey: "mattermost" }
245
+ }),
248
246
  streaming: {
249
247
  label: "Mattermost Streaming Mode",
250
248
  help: "Unified Mattermost stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\". \"progress\" keeps a single editable progress draft until final delivery."
@@ -253,30 +251,10 @@ const MattermostChannelConfigSchema = buildChannelConfigSchema(MattermostAccount
253
251
  label: "Mattermost Streaming Mode",
254
252
  help: "Canonical Mattermost preview mode: \"off\" | \"partial\" | \"block\" | \"progress\"."
255
253
  },
256
- "streaming.progress.label": {
257
- label: "Mattermost Progress Label",
258
- help: "Initial progress draft title. Use \"auto\" for built-in single-word labels, a custom string, or false to hide the title."
259
- },
260
- "streaming.progress.labels": {
261
- label: "Mattermost Progress Label Pool",
262
- help: "Candidate labels for streaming.progress.label=\"auto\". Leave unset to use OpenClaw built-in progress labels."
263
- },
264
- "streaming.progress.maxLines": {
265
- label: "Mattermost Progress Max Lines",
266
- help: "Maximum number of compact progress lines to keep below the draft label (default: 8)."
267
- },
268
- "streaming.progress.maxLineChars": {
269
- label: "Mattermost Progress Max Line Chars",
270
- help: "Maximum characters per compact progress line before truncation (default: 120). Prose cuts at word boundaries; commands and paths keep useful suffixes."
271
- },
272
- "streaming.progress.toolProgress": {
273
- label: "Mattermost Progress Tool Lines",
274
- help: "Show compact tool/progress lines in progress draft mode (default: true). Set false to keep only the label until final delivery."
275
- },
276
- "streaming.progress.commandText": {
277
- label: "Mattermost Progress Command Text",
278
- help: "Command/exec detail in progress draft lines: \"raw\" preserves released behavior; \"status\" shows only the tool label."
279
- },
254
+ ...createChannelConfigUiHints({
255
+ channelLabel: "Mattermost",
256
+ progress: {}
257
+ }),
280
258
  "streaming.preview.toolProgress": {
281
259
  label: "Mattermost Draft Tool Progress",
282
260
  help: "Show tool/progress activity in the live draft preview post (default: true). Set false to hide interim tool updates while the draft preview stays active."
@@ -294,28 +272,13 @@ const MattermostChannelConfigSchema = buildChannelConfigSchema(MattermostAccount
294
272
  help: "Merge streamed Mattermost block replies before final delivery."
295
273
  }
296
274
  } });
297
- //#endregion
298
- //#region extensions/mattermost/src/doctor.ts
299
- function isMattermostMutableAllowEntry(raw) {
300
- const text = raw.trim();
301
- if (!text || text === "*") return false;
302
- const lowered = normalizeLowercaseStringOrEmpty(text.replace(/^(mattermost|user):/i, "").replace(/^@/, "").trim());
303
- if (/^[a-z0-9]{26}$/.test(lowered)) return false;
304
- return true;
305
- }
306
275
  const mattermostDoctor = {
307
276
  legacyConfigRules,
308
277
  normalizeCompatibilityConfig,
309
278
  collectMutableAllowlistWarnings: createDangerousNameMatchingMutableAllowlistWarningCollector({
310
279
  channel: "mattermost",
311
- detector: isMattermostMutableAllowEntry,
312
- collectLists: (scope) => [{
313
- pathLabel: `${scope.prefix}.allowFrom`,
314
- list: scope.account.allowFrom
315
- }, {
316
- pathLabel: `${scope.prefix}.groupAllowFrom`,
317
- list: scope.account.groupAllowFrom
318
- }]
280
+ detector: buildMutableAllowEntryDetector({ stableIdPattern: /^(?:(?:mattermost|user):)?@?[a-z0-9]{26}$/i }),
281
+ collectLists: (scope) => collectStandardAllowlistLists(scope)
319
282
  })
320
283
  };
321
284
  //#endregion
@@ -325,13 +288,11 @@ function resolveMattermostGroupRequireMention(params) {
325
288
  cfg: params.cfg,
326
289
  accountId: params.accountId
327
290
  });
328
- const requireMentionOverride = typeof params.requireMentionOverride === "boolean" ? params.requireMentionOverride : account.requireMention;
329
- return resolveChannelGroupRequireMention({
330
- cfg: params.cfg,
331
- channel: "mattermost",
332
- groupId: params.groupId,
333
- accountId: params.accountId,
334
- requireMentionOverride
291
+ return resolveScopeRequireMention({
292
+ tree: buildChannelGroupsScopeTree(params.cfg, "mattermost", params.accountId),
293
+ path: params.groupId ? [params.groupId] : [],
294
+ requireMentionOverride: params.requireMentionOverride ?? account.requireMention,
295
+ overrideOrder: "after-config"
335
296
  });
336
297
  }
337
298
  //#endregion
@@ -515,60 +476,50 @@ const mattermostSetupWizard = {
515
476
  patch: {}
516
477
  })
517
478
  },
518
- credentials: [{
479
+ credentials: [defineTokenCredential({
519
480
  inputKey: "botToken",
481
+ configKey: "botToken",
520
482
  providerHint: channel,
521
483
  credentialLabel: t("wizard.mattermost.botToken"),
522
484
  preferredEnvVar: "MATTERMOST_BOT_TOKEN",
523
485
  envPrompt: t("wizard.mattermost.envPrompt"),
524
486
  keepPrompt: t("wizard.mattermost.botTokenKeep"),
525
487
  inputPrompt: t("wizard.mattermost.botTokenInput"),
526
- inspect: ({ cfg, accountId }) => {
527
- const resolvedAccount = resolveMattermostAccountWithSecrets(cfg, accountId);
528
- return {
529
- accountConfigured: isMattermostConfigured(resolvedAccount),
530
- hasConfiguredValue: hasConfiguredSecretInput(resolvedAccount.config.botToken)
531
- };
532
- },
533
- applySet: async ({ cfg, accountId, value }) => applyMattermostSetupConfigPatch({
488
+ resolveAccount: ({ cfg, accountId }) => resolveMattermostAccountWithSecrets(cfg, accountId),
489
+ accountConfigured: isMattermostConfigured,
490
+ patchAccount: ({ cfg, accountId, patch }) => applyMattermostSetupConfigPatch({
534
491
  cfg,
535
492
  accountId,
536
- patch: { botToken: value }
537
- })
538
- }],
539
- textInputs: [{
493
+ patch
494
+ }),
495
+ set: {}
496
+ })],
497
+ textInputs: [baseUrlTextInput({
540
498
  inputKey: "httpUrl",
499
+ configKey: "baseUrl",
541
500
  message: t("wizard.mattermost.baseUrlPrompt"),
542
501
  confirmCurrentValue: false,
543
- currentValue: ({ cfg, accountId }) => resolveMattermostAccountWithSecrets(cfg, accountId).baseUrl ?? process.env.MATTERMOST_URL?.trim(),
544
- initialValue: ({ cfg, accountId }) => resolveMattermostAccountWithSecrets(cfg, accountId).baseUrl ?? process.env.MATTERMOST_URL?.trim(),
502
+ resolveAccount: ({ cfg, accountId }) => resolveMattermostAccountWithSecrets(cfg, accountId),
503
+ currentValue: (account) => account.baseUrl ?? process.env.MATTERMOST_URL?.trim(),
504
+ includeInitialValue: true,
545
505
  shouldPrompt: ({ cfg, accountId, credentialValues, currentValue }) => {
546
506
  const resolvedAccount = resolveMattermostAccountWithSecrets(cfg, accountId);
547
507
  const tokenConfigured = Boolean(resolvedAccount.botToken?.trim()) || hasConfiguredSecretInput(resolvedAccount.config.botToken);
548
508
  return Boolean(credentialValues.botToken) || !tokenConfigured || !currentValue;
549
509
  },
550
- validate: ({ value }) => normalizeMattermostBaseUrl(value) ? void 0 : "Mattermost base URL must include a valid base URL.",
551
- normalizeValue: ({ value }) => normalizeMattermostBaseUrl(value) ?? value.trim(),
552
- applySet: async ({ cfg, accountId, value }) => applyMattermostSetupConfigPatch({
510
+ validate: (value) => normalizeMattermostBaseUrl(value) ? void 0 : "Mattermost base URL must include a valid base URL.",
511
+ normalize: (value) => normalizeMattermostBaseUrl(value) ?? value.trim(),
512
+ patchAccount: ({ cfg, accountId, patch }) => applyMattermostSetupConfigPatch({
553
513
  cfg,
554
514
  accountId,
555
- patch: { baseUrl: value }
515
+ patch
556
516
  })
557
- }],
558
- disable: (cfg) => ({
559
- ...cfg,
560
- channels: {
561
- ...cfg.channels,
562
- mattermost: {
563
- ...cfg.channels?.mattermost,
564
- enabled: false
565
- }
566
- }
567
- })
517
+ })],
518
+ disable: (cfg) => setSetupChannelEnabled(cfg, channel, false)
568
519
  };
569
520
  //#endregion
570
521
  //#region extensions/mattermost/src/channel.ts
571
- const loadMattermostChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-D0SJSEei.js"));
522
+ const loadMattermostChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-CKb2-z0p.js"));
572
523
  function buildMattermostPresentationButtons(presentation) {
573
524
  return presentation.blocks.filter((block) => block.type === "buttons").map((block) => block.buttons.flatMap((button) => {
574
525
  if (button.action) return [];
@@ -590,8 +541,11 @@ const MATTERMOST_PRESENTATION_CAPABILITIES = {
590
541
  divider: false,
591
542
  limits: { text: { markdownDialect: "markdown" } }
592
543
  };
593
- function hasMattermostPresentationButtons(presentation) {
594
- return buildMattermostPresentationButtons(presentation).some((row) => row.length > 0);
544
+ function hasMattermostPresentationNavigation(presentation) {
545
+ return presentation.blocks.some((block) => block.type === "buttons" && block.buttons.some((button) => {
546
+ const action = resolveMessagePresentationButtonAction(button);
547
+ return action?.type === "url" || action?.type === "web-app" && Boolean(action.url);
548
+ }));
595
549
  }
596
550
  function readMattermostPresentationButtons(payload) {
597
551
  const buttons = (payload.channelData?.mattermost)?.presentationButtons;
@@ -728,21 +682,26 @@ const mattermostMessageActions = {
728
682
  supportsAction: ({ action }) => {
729
683
  return action === "send" || action === "react";
730
684
  },
731
- handleAction: async ({ action, params, cfg, accountId, mediaAccess, mediaLocalRoots, mediaReadFile }) => {
685
+ handleAction: async ({ action, params, cfg, accountId, mediaAccess, mediaLocalRoots, mediaReadFile, conversationReadOrigin }) => {
732
686
  if (action === "react") {
733
687
  const resolvedAccountId = accountId ?? resolveDefaultMattermostAccountId(cfg);
734
688
  const mattermostConfig = cfg.channels?.mattermost;
735
- if (!(resolveMattermostAccount({
689
+ const account = resolveMattermostAccount({
736
690
  cfg,
737
691
  accountId: resolvedAccountId
738
- }).config.actions?.reactions ?? mattermostConfig?.actions?.reactions ?? true)) throw new Error("Mattermost reactions are disabled in config");
692
+ });
693
+ if (!account.enabled) throw new Error(`Mattermost account "${resolvedAccountId}" is disabled`);
694
+ if (!(account.config.actions?.reactions ?? mattermostConfig?.actions?.reactions ?? true)) throw new Error("Mattermost reactions are disabled in config");
739
695
  const { postId, emojiName, remove } = parseMattermostReactActionParams(params);
696
+ const authorizedTarget = normalizeOptionalString(params.to);
740
697
  if (remove) {
741
698
  const result = await (await loadMattermostChannelRuntime()).removeMattermostReaction({
742
699
  cfg,
743
700
  postId,
744
701
  emojiName,
745
- accountId: resolvedAccountId
702
+ accountId: resolvedAccountId,
703
+ authorizedTarget,
704
+ conversationReadOrigin
746
705
  });
747
706
  if (!result.ok) throw new Error(result.error);
748
707
  return {
@@ -757,7 +716,9 @@ const mattermostMessageActions = {
757
716
  cfg,
758
717
  postId,
759
718
  emojiName,
760
- accountId: resolvedAccountId
719
+ accountId: resolvedAccountId,
720
+ authorizedTarget,
721
+ conversationReadOrigin
761
722
  });
762
723
  if (!result.ok) throw new Error(result.error);
763
724
  return {
@@ -871,13 +832,12 @@ function collectMattermostAttachmentMedia(params) {
871
832
  readMattermostStringParam(params, "fileUrl")
872
833
  ];
873
834
  mediaUrlCandidates.push(...readMattermostStringArrayParam(params, "mediaUrls"));
874
- let hasUnsupportedAttachmentPayload = typeof params.buffer === "string" || typeof params.base64 === "string";
835
+ let hasUnsupportedAttachmentPayload = Boolean(readMattermostStringParam(params, "buffer") ?? readMattermostStringParam(params, "base64"));
875
836
  if (Array.isArray(params.attachments)) for (const attachment of params.attachments) {
876
837
  if (!attachment || typeof attachment !== "object" || Array.isArray(attachment)) continue;
877
838
  const record = attachment;
878
839
  mediaUrlCandidates.push(readMattermostStringParam(record, "media"), readMattermostStringParam(record, "mediaUrl"), readMattermostStringParam(record, "path"), readMattermostStringParam(record, "filePath"), readMattermostStringParam(record, "fileUrl"), readMattermostStringParam(record, "url"));
879
- hasUnsupportedAttachmentPayload ||= typeof record.buffer === "string";
880
- hasUnsupportedAttachmentPayload ||= typeof record.base64 === "string";
840
+ hasUnsupportedAttachmentPayload ||= Boolean(readMattermostStringParam(record, "buffer") ?? readMattermostStringParam(record, "base64"));
881
841
  }
882
842
  return {
883
843
  mediaUrls: collectNonBlankStrings(mediaUrlCandidates),
@@ -902,20 +862,21 @@ const mattermostOutbound = {
902
862
  renderPresentation: ({ payload, presentation }) => {
903
863
  if (payload.mediaUrls && payload.mediaUrls.length > 1) return null;
904
864
  const buttons = buildMattermostPresentationButtons(presentation);
905
- if (!hasMattermostPresentationButtons(presentation)) return null;
865
+ const hasButtons = buttons.some((row) => row.length > 0);
866
+ if (!hasButtons && !hasMattermostPresentationNavigation(presentation)) return null;
906
867
  return {
907
868
  ...payload,
908
869
  text: renderMessagePresentationFallbackText({
909
870
  text: payload.text,
910
871
  presentation
911
872
  }),
912
- channelData: {
873
+ ...hasButtons ? { channelData: {
913
874
  ...payload.channelData,
914
875
  mattermost: {
915
876
  ...payload.channelData?.mattermost,
916
877
  presentationButtons: buttons
917
878
  }
918
- }
879
+ } } : {}
919
880
  };
920
881
  },
921
882
  sendPayload: async (ctx) => {
@@ -1035,6 +996,8 @@ const mattermostPlugin = createChatChannelPlugin({
1035
996
  }),
1036
997
  messaging: {
1037
998
  targetPrefixes: ["mattermost"],
999
+ directTargetStyle: "user-prefixed",
1000
+ targetIdComparison: "case-sensitive",
1038
1001
  defaultMarkdownTableMode: "off",
1039
1002
  normalizeTarget: normalizeMattermostMessagingTarget,
1040
1003
  resolveDeliveryTarget: ({ conversationId, parentConversationId }) => {
@@ -1100,7 +1063,7 @@ const mattermostPlugin = createChatChannelPlugin({
1100
1063
  })
1101
1064
  }),
1102
1065
  gateway: {
1103
- resolveGatewayAuthBypassPaths: ({ cfg }) => resolveMattermostGatewayAuthBypassPaths(cfg),
1066
+ resolveGatewayAuthBypassPaths: resolveMattermostGatewayAuthBypassPaths,
1104
1067
  startAccount: async (ctx) => {
1105
1068
  const account = ctx.account;
1106
1069
  const statusSink = createAccountStatusSink({
@@ -1150,9 +1113,10 @@ const mattermostPlugin = createChatChannelPlugin({
1150
1113
  }),
1151
1114
  resolveReplyTransport: ({ threadId, replyToId, replyToIsExplicit, replyDelivery }) => {
1152
1115
  const ambientThreadId = threadId != null ? String(threadId) : void 0;
1153
- const resolvedThreadId = replyDelivery?.chatType === "direct" ? void 0 : replyDelivery ? replyToIsExplicit ? replyToId ?? ambientThreadId : ambientThreadId ?? replyToId ?? void 0 : ambientThreadId ?? replyToId;
1116
+ const isFlatDirect = replyDelivery?.chatType === "direct" && replyDelivery.replyToMode === "off";
1117
+ const resolvedThreadId = isFlatDirect ? void 0 : replyDelivery ? replyToIsExplicit ? replyToId ?? ambientThreadId : ambientThreadId ?? replyToId ?? void 0 : ambientThreadId ?? replyToId;
1154
1118
  return {
1155
- replyToId: replyDelivery?.chatType === "direct" ? null : resolvedThreadId,
1119
+ replyToId: isFlatDirect ? null : resolvedThreadId,
1156
1120
  threadId: resolvedThreadId ?? null
1157
1121
  };
1158
1122
  }
@@ -1161,4 +1125,4 @@ const mattermostPlugin = createChatChannelPlugin({
1161
1125
  outbound: mattermostOutbound
1162
1126
  });
1163
1127
  //#endregion
1164
- export { describeMattermostAccount as a, mattermostMeta as c, MattermostChannelConfigSchema as i, mattermostSetupWizard as n, isMattermostConfigured$1 as o, mattermostSetupAdapter as r, mattermostConfigAdapter as s, mattermostPlugin as t };
1128
+ export { MattermostChannelConfigSchema as a, mattermostConfigAdapter as c, normalizeMattermostMessagingTarget as i, mattermostMeta as l, mattermostSetupWizard as n, describeMattermostAccount as o, mattermostSetupAdapter as r, isMattermostConfigured$1 as s, mattermostPlugin as t };
@@ -1,2 +1,2 @@
1
- import { t as mattermostPlugin } from "./channel-plugin-runtime-DhS8rwfs.js";
1
+ import { t as mattermostPlugin } from "./channel-plugin-runtime-BXmjNn6B.js";
2
2
  export { mattermostPlugin };