@openclaw/mattermost 2026.7.1-beta.1 → 2026.7.1-beta.4

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.
@@ -13,7 +13,7 @@ import { z } from "zod";
13
13
  //#region extensions/mattermost/src/mattermost/client.ts
14
14
  const MATTERMOST_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
15
15
  const MATTERMOST_TEXT_RESPONSE_LIMIT_BYTES = 64 * 1024;
16
- const NULL_BODY_STATUSES = new Set([
16
+ const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([
17
17
  101,
18
18
  204,
19
19
  205,
@@ -183,7 +183,7 @@ function resolveMattermostReplyDeliveryBarrierTimeoutMs(params) {
183
183
  const totalTimeoutMs = perDeliveryTimeoutMs * deliveryCount + Math.max(0, params.humanDelayBudgetMs ?? 0);
184
184
  return resolveTimerTimeoutMs(Number.isFinite(totalTimeoutMs) ? totalTimeoutMs : Number.MAX_SAFE_INTEGER, perDeliveryTimeoutMs);
185
185
  }
186
- const RETRYABLE_NETWORK_ERROR_CODES = new Set([
186
+ const RETRYABLE_NETWORK_ERROR_CODES = /* @__PURE__ */ new Set([
187
187
  "ECONNRESET",
188
188
  "ECONNREFUSED",
189
189
  "ETIMEDOUT",
@@ -201,7 +201,7 @@ const RETRYABLE_NETWORK_ERROR_CODES = new Set([
201
201
  "UND_ERR_HEADERS_TIMEOUT",
202
202
  "UND_ERR_BODY_TIMEOUT"
203
203
  ]);
204
- const RETRYABLE_NETWORK_ERROR_NAMES = new Set([
204
+ const RETRYABLE_NETWORK_ERROR_NAMES = /* @__PURE__ */ new Set([
205
205
  "AbortError",
206
206
  "TimeoutError",
207
207
  "ConnectTimeoutError",
@@ -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-C7gpYyYd.js";
2
- import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-BHgOAkk8.js";
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";
3
3
  //#region extensions/mattermost/src/channel.setup.ts
4
4
  const mattermostSetupPlugin = {
5
5
  id: "mattermost",
@@ -1,5 +1,5 @@
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-Bt60MyHp.js";
2
- import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-BHgOAkk8.js";
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
3
  import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-ttH0DCuq.js";
4
4
  import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Cx0LUNXy.js";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
@@ -17,11 +17,11 @@ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
17
17
  import { resolvePayloadMediaUrls, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
18
18
  import { isPrivateNetworkOptInEnabled } from "openclaw/plugin-sdk/ssrf-runtime";
19
19
  import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
20
+ import { chunkTextForOutbound, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
20
21
  import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
21
22
  import { describeAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
22
23
  import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk/account-id";
23
24
  import { z } from "zod";
24
- import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
25
25
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
26
26
  import { BlockStreamingCoalesceSchema, DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, buildChannelConfigSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-primitives";
27
27
  import { applyAccountNameToChannelSection, applySetupAccountConfigPatch, createSetupTranslator, createStandardChannelSetupStatus, formatDocsLink, migrateBaseNameToDefaultAccount } from "openclaw/plugin-sdk/setup";
@@ -380,12 +380,15 @@ function resolveMattermostOutboundSessionRoute(params) {
380
380
  if (trimmed.startsWith("@")) trimmed = trimmed.slice(1).trim();
381
381
  const rawId = stripTargetKindPrefix(trimmed);
382
382
  if (!rawId) return null;
383
+ const hasExplicitUserKind = resolvedKind === "user" || lower.startsWith("user:");
384
+ const recipientSessionExact = isUser && hasExplicitUserKind && /^[a-z0-9]{26}$/.test(rawId);
383
385
  return buildThreadAwareOutboundSessionRoute({
384
386
  route: buildChannelOutboundSessionRoute({
385
387
  cfg: params.cfg,
386
388
  agentId: params.agentId,
387
389
  channel: "mattermost",
388
390
  accountId: params.accountId,
391
+ recipientSessionExact,
389
392
  peer: {
390
393
  kind: isUser ? "direct" : "channel",
391
394
  id: rawId
@@ -565,7 +568,7 @@ const mattermostSetupWizard = {
565
568
  };
566
569
  //#endregion
567
570
  //#region extensions/mattermost/src/channel.ts
568
- const loadMattermostChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-BfOTGtEU.js"));
571
+ const loadMattermostChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-D0SJSEei.js"));
569
572
  function buildMattermostPresentationButtons(presentation) {
570
573
  return presentation.blocks.filter((block) => block.type === "buttons").map((block) => block.buttons.flatMap((button) => {
571
574
  if (button.action) return [];
@@ -886,6 +889,7 @@ const mattermostOutbound = {
886
889
  chunker: chunkTextForOutbound,
887
890
  chunkerMode: "markdown",
888
891
  textChunkLimit: 4e3,
892
+ sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text),
889
893
  deliveryCapabilities: { durableFinal: {
890
894
  text: true,
891
895
  media: true,
@@ -1,2 +1,2 @@
1
- import { t as mattermostPlugin } from "./channel-plugin-runtime-C7gpYyYd.js";
1
+ import { t as mattermostPlugin } from "./channel-plugin-runtime-DhS8rwfs.js";
2
2
  export { mattermostPlugin };
@@ -1,9 +1,9 @@
1
1
  import { C as resolveChannelMediaMaxBytes, E as warnMissingProviderGroupPolicyFallbackOnce, S as resolveAllowlistProviderRuntimeGroupPolicy, T as resolveDefaultGroupPolicy, _ as logInboundDrop, c as buildAgentMediaPayload, d as createChannelMessageReplyPipeline, f as createChannelPairingController, h as listSkillCommandsForAgents, i as normalizeMattermostAllowEntry, l as buildModelsProviderData, n as formatMattermostDirectMessageDropLog, o as resolveMattermostMonitorInboundAccess, s as DEFAULT_GROUP_HISTORY_LIMIT, t as authorizeMattermostCommandInvocation, u as createChannelHistoryWindow, v as logTypingFailure, x as registerPluginHttpRoute, y as parseTcpPort } from "./monitor-auth-BiDuyvOc.js";
2
- import { _ as readMattermostError, a as MattermostPostSchema, b as updateMattermostPost, c as createMattermostPost, f as fetchMattermostMe, g as normalizeMattermostBaseUrl, h as fetchMattermostUserTeams, i as resolveMattermostReplyToMode, l as deleteMattermostPost, o as createMattermostClient, p as fetchMattermostUser, r as resolveMattermostAccount, t as listMattermostAccountIds, u as fetchMattermostChannel, y as sendMattermostTyping } from "./accounts-Bt60MyHp.js";
2
+ import { _ as readMattermostError, a as MattermostPostSchema, b as updateMattermostPost, c as createMattermostPost, f as fetchMattermostMe, g as normalizeMattermostBaseUrl, h as fetchMattermostUserTeams, i as resolveMattermostReplyToMode, l as deleteMattermostPost, o as createMattermostClient, p as fetchMattermostUser, r as resolveMattermostAccount, t as listMattermostAccountIds, u as fetchMattermostChannel, y as sendMattermostTyping } from "./accounts-ITTlduDO.js";
3
3
  import { n as getOptionalMattermostRuntime, t as getMattermostRuntime } from "./runtime-CNB4YGqJ.js";
4
- import { C as registerSlashCommands, S as isSlashCommandsEnabled, T as resolveSlashCommandConfig, _ as renderMattermostModelsPickerView, a as sendMessageMattermost, b as DEFAULT_COMMAND_SPECS, c as computeInteractionCallbackUrl, d as setInteractionCallbackUrl, f as setInteractionSecret, g as parseMattermostModelPickerContext, h as buildMattermostAllowedModelRefs, l as createMattermostInteractionHandler, m as deliverMattermostReplyPayload, n as deactivateSlashCommands, o as resolveMattermostOpaqueTarget, p as createMattermostReplyDeliveryBarrier, r as getSlashCommandState, s as buildButtonProps, t as activateSlashCommands, u as resolveInteractionCallbackPath, v as renderMattermostProviderPickerView, w as resolveCallbackUrl, x as cleanupSlashCommands, y as resolveMattermostModelPickerCurrentModel } from "./slash-state-D1lza2ZZ.js";
4
+ import { C as registerSlashCommands, S as isSlashCommandsEnabled, T as resolveSlashCommandConfig, _ as renderMattermostModelsPickerView, a as sendMessageMattermost, b as DEFAULT_COMMAND_SPECS, c as computeInteractionCallbackUrl, d as setInteractionCallbackUrl, f as setInteractionSecret, g as parseMattermostModelPickerContext, h as buildMattermostAllowedModelRefs, l as createMattermostInteractionHandler, m as deliverMattermostReplyPayload, n as deactivateSlashCommands, o as resolveMattermostOpaqueTarget, p as createMattermostReplyDeliveryBarrier, r as getSlashCommandState, s as buildButtonProps, t as activateSlashCommands, u as resolveInteractionCallbackPath, v as renderMattermostProviderPickerView, w as resolveCallbackUrl, x as cleanupSlashCommands, y as resolveMattermostModelPickerCurrentModel } from "./slash-state-BfOSlkmn.js";
5
5
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringEntries, normalizeTrimmedStringList, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
6
- import { formatInboundFromLabel } from "openclaw/plugin-sdk/channel-inbound";
6
+ import { formatInboundFromLabel, formatInboundMediaUnavailableText } from "openclaw/plugin-sdk/channel-inbound";
7
7
  import { buildChannelProgressDraftLineForEntry, createChannelProgressDraftCompositor, createFinalizableDraftLifecycle, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, resolveChannelStreamingPreviewToolProgress } from "openclaw/plugin-sdk/channel-outbound";
8
8
  import { rawDataToString } from "openclaw/plugin-sdk/webhook-ingress";
9
9
  import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs, resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
@@ -20,7 +20,7 @@ import { createClaimableDedupe } from "openclaw/plugin-sdk/persistent-dedupe";
20
20
  import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
21
21
  import { captureWsEvent, createDebugProxyWebSocketAgent, resolveDebugProxySettings } from "openclaw/plugin-sdk/proxy-capture";
22
22
  import WebSocket from "ws";
23
- import { resolveGlobalDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
23
+ import { createPersistentDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
24
24
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
25
25
  //#region extensions/mattermost/src/mattermost/directory.ts
26
26
  function buildClient(params) {
@@ -105,7 +105,7 @@ async function listMattermostDirectoryGroups(params) {
105
105
  * user list (unlike channels where membership varies). Uses the first team
106
106
  * returned — multi-team setups will only see members from that team.
107
107
  *
108
- * NOTE: per_page=200 for member listing; same pagination caveat as groups.
108
+ * Uses paginated member listing with per_page=200, the Mattermost API maximum.
109
109
  */
110
110
  async function listMattermostDirectoryPeers(params) {
111
111
  const clients = buildClients(params);
@@ -126,12 +126,22 @@ async function listMattermostDirectoryPeers(params) {
126
126
  })
127
127
  });
128
128
  else {
129
- const userIds = (await client.request(`/teams/${teamId}/members?per_page=200`)).map((m) => m.user_id).filter((id) => id !== me.id);
129
+ const pageSize = 200;
130
+ const userIds = [];
131
+ for (let page = 0;; page += 1) {
132
+ const pageMembers = await client.request(`/teams/${teamId}/members?page=${page}&per_page=${pageSize}`);
133
+ for (const member of pageMembers) if (member.user_id !== me.id) userIds.push(member.user_id);
134
+ if (pageMembers.length < pageSize) break;
135
+ }
130
136
  if (!userIds.length) return [];
131
- users = await client.request("/users/ids", {
132
- method: "POST",
133
- body: JSON.stringify(userIds)
134
- });
137
+ users = [];
138
+ for (let index = 0; index < userIds.length; index += pageSize) {
139
+ const userIdBatch = userIds.slice(index, index + pageSize);
140
+ users.push(...await client.request("/users/ids", {
141
+ method: "POST",
142
+ body: JSON.stringify(userIdBatch)
143
+ }));
144
+ }
135
145
  }
136
146
  const entries = users.filter((u) => u.id !== me.id).map((u) => ({
137
147
  kind: "user",
@@ -328,6 +338,15 @@ function stripOncharPrefix(text, prefixes) {
328
338
  }
329
339
  //#endregion
330
340
  //#region extensions/mattermost/src/mattermost/monitor-resources.ts
341
+ function formatMattermostInboundMediaText(params) {
342
+ const unavailableCount = Math.max(0, params.expectedCount - params.mediaCount);
343
+ if (unavailableCount === 0) return params.body;
344
+ return formatInboundMediaUnavailableText({
345
+ body: params.body,
346
+ mediaPlaceholder: params.mediaCount === 0 ? params.mediaPlaceholder : void 0,
347
+ notice: `[mattermost ${unavailableCount > 1 ? `${unavailableCount} attachments` : "attachment"} unavailable]`
348
+ });
349
+ }
331
350
  const CHANNEL_CACHE_TTL_MS = 5 * 6e4;
332
351
  const USER_CACHE_TTL_MS = 10 * 6e4;
333
352
  function createMattermostMonitorResources(params) {
@@ -545,6 +564,7 @@ async function registerMattermostMonitorSlashCommands(params) {
545
564
  }
546
565
  //#endregion
547
566
  //#region extensions/mattermost/src/mattermost/monitor-websocket.ts
567
+ const MATTERMOST_WEBSOCKET_MAX_PAYLOAD_BYTES = 16 * 1024 * 1024;
548
568
  const MattermostEventPayloadSchema = z.object({
549
569
  event: z.string().optional(),
550
570
  data: z.object({
@@ -580,7 +600,10 @@ var WebSocketClosedBeforeOpenError = class extends Error {
580
600
  };
581
601
  const defaultMattermostWebSocketFactory = (url) => {
582
602
  const agent = createDebugProxyWebSocketAgent(resolveDebugProxySettings());
583
- return new WebSocket(url, agent ? { agent } : void 0);
603
+ return new WebSocket(url, {
604
+ ...agent ? { agent } : {},
605
+ maxPayload: MATTERMOST_WEBSOCKET_MAX_PAYLOAD_BYTES
606
+ });
584
607
  };
585
608
  function parsePostedPayload(payload) {
586
609
  if (payload.event !== "posted") return null;
@@ -935,88 +958,37 @@ function sleepAbortable(ms, signal) {
935
958
  }
936
959
  //#endregion
937
960
  //#region extensions/mattermost/src/mattermost/thread-participation.ts
938
- /**
939
- * In-memory + persisted cache of Mattermost threads the bot has replied in.
940
- * Lets the bot auto-respond to thread follow-ups without a re-mention after its
941
- * first visible reply. Mirrors the Slack `sent-thread-cache` dual-layer pattern.
942
- */
943
- const TTL_MS = 10080 * 60 * 1e3;
944
- const MAX_ENTRIES = 5e3;
945
- const PERSISTENT_MAX_ENTRIES = 1e3;
946
- const PERSISTENT_NAMESPACE = "mattermost.thread-participation";
947
- const threadParticipation = resolveGlobalDedupeCache(Symbol.for("openclaw.mattermostThreadParticipation"), {
948
- ttlMs: TTL_MS,
949
- maxSize: MAX_ENTRIES
961
+ const threadParticipation = createPersistentDedupeCache({
962
+ globalKey: Symbol.for("openclaw.mattermostThreadParticipation"),
963
+ ttlMs: 10080 * 60 * 1e3,
964
+ maxSize: 5e3,
965
+ persistent: {
966
+ namespace: "mattermost.thread-participation",
967
+ maxEntries: 1e3,
968
+ openStore: (options) => getOptionalMattermostRuntime()?.state.openKeyedStore(options),
969
+ logError: (error) => {
970
+ try {
971
+ getOptionalMattermostRuntime()?.logging.getChildLogger({
972
+ plugin: "mattermost",
973
+ feature: "thread-participation-state"
974
+ }).warn("Mattermost persistent thread participation state failed", { error: String(error) });
975
+ } catch {}
976
+ }
977
+ }
950
978
  });
951
- let persistentStore;
952
- let persistentStoreDisabled = false;
953
979
  function makeKey(accountId, channelId, threadRootId) {
954
980
  return `${accountId}:${channelId}:${threadRootId}`;
955
981
  }
956
- function reportPersistentThreadParticipationError(error) {
957
- try {
958
- getOptionalMattermostRuntime()?.logging.getChildLogger({
959
- plugin: "mattermost",
960
- feature: "thread-participation-state"
961
- }).warn("Mattermost persistent thread participation state failed", { error: String(error) });
962
- } catch {}
963
- }
964
- function disablePersistentThreadParticipation(error) {
965
- persistentStoreDisabled = true;
966
- persistentStore = void 0;
967
- reportPersistentThreadParticipationError(error);
968
- }
969
- function getPersistentThreadParticipationStore() {
970
- if (persistentStoreDisabled) return;
971
- if (persistentStore) return persistentStore;
972
- const runtime = getOptionalMattermostRuntime();
973
- if (!runtime) return;
974
- try {
975
- persistentStore = runtime.state.openKeyedStore({
976
- namespace: PERSISTENT_NAMESPACE,
977
- maxEntries: PERSISTENT_MAX_ENTRIES,
978
- defaultTtlMs: TTL_MS
979
- });
980
- return persistentStore;
981
- } catch (error) {
982
- disablePersistentThreadParticipation(error);
983
- return;
984
- }
985
- }
986
- function rememberPersistentThreadParticipation(params) {
987
- const store = getPersistentThreadParticipationStore();
988
- if (!store) return;
989
- store.register(params.key, {
990
- ...params.agentId ? { agentId: params.agentId } : {},
991
- repliedAt: Date.now()
992
- }).catch(disablePersistentThreadParticipation);
993
- }
994
- async function lookupPersistentThreadParticipation(key) {
995
- const store = getPersistentThreadParticipationStore();
996
- if (!store) return false;
997
- try {
998
- return Boolean(await store.lookup(key));
999
- } catch (error) {
1000
- disablePersistentThreadParticipation(error);
1001
- return false;
1002
- }
1003
- }
1004
982
  function recordMattermostThreadParticipation(accountId, channelId, threadRootId, opts) {
1005
983
  if (!accountId || !channelId || !threadRootId) return;
1006
- const key = makeKey(accountId, channelId, threadRootId);
1007
- threadParticipation.check(key);
1008
- rememberPersistentThreadParticipation({
1009
- key,
1010
- agentId: opts?.agentId
984
+ threadParticipation.register(makeKey(accountId, channelId, threadRootId), {
985
+ ...opts?.agentId ? { agentId: opts.agentId } : {},
986
+ repliedAt: Date.now()
1011
987
  });
1012
988
  }
1013
989
  async function hasMattermostThreadParticipationWithPersistence(params) {
1014
990
  if (!params.accountId || !params.channelId || !params.threadRootId) return false;
1015
- const key = makeKey(params.accountId, params.channelId, params.threadRootId);
1016
- if (threadParticipation.peek(key)) return true;
1017
- const found = await lookupPersistentThreadParticipation(key);
1018
- if (found) threadParticipation.check(key);
1019
- return found;
991
+ return await threadParticipation.lookup(makeKey(params.accountId, params.channelId, params.threadRootId));
1020
992
  }
1021
993
  //#endregion
1022
994
  //#region extensions/mattermost/src/mattermost/monitor.ts
@@ -1998,9 +1970,15 @@ async function monitorMattermostProvider(opts = {}) {
1998
1970
  recordPendingHistory();
1999
1971
  return;
2000
1972
  }
2001
- const mediaList = await resolveMattermostMedia(post.file_ids);
1973
+ const fileIds = uniqueStrings(normalizeTrimmedStringList(post.file_ids ?? []));
1974
+ const mediaList = await resolveMattermostMedia(fileIds);
2002
1975
  const mediaPlaceholder = buildMattermostAttachmentPlaceholder(mediaList);
2003
- const bodyText = normalizeMention([oncharTriggered ? oncharResult.stripped : rawText, mediaPlaceholder].filter(Boolean).join("\n").trim(), botUsername);
1976
+ const bodyText = normalizeMention(formatMattermostInboundMediaText({
1977
+ body: [oncharTriggered ? oncharResult.stripped : rawText, mediaPlaceholder].filter(Boolean).join("\n").trim(),
1978
+ mediaPlaceholder,
1979
+ expectedCount: fileIds.length,
1980
+ mediaCount: mediaList.length
1981
+ }), botUsername);
2004
1982
  if (shouldDropEmptyMattermostBody({
2005
1983
  bodyText,
2006
1984
  rawText: rawPostText,
@@ -2059,7 +2037,7 @@ async function monitorMattermostProvider(opts = {}) {
2059
2037
  Body: combinedBody,
2060
2038
  BodyForAgent: bodyForAgent,
2061
2039
  InboundHistory: inboundHistory,
2062
- RawBody: bodyText,
2040
+ RawBody: commandBody,
2063
2041
  CommandBody: commandBody,
2064
2042
  BodyForCommands: commandBody,
2065
2043
  From: kind === "direct" ? `mattermost:${senderId}` : kind === "group" ? `mattermost:group:${channelId}` : `mattermost:channel:${channelId}`,
@@ -1,2 +1,2 @@
1
- import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-BHgOAkk8.js";
1
+ import { t as resolveMattermostGatewayAuthBypassPaths } from "./gateway-auth-bypass-BIXLORHU.js";
2
2
  export { resolveMattermostGatewayAuthBypassPaths as resolveGatewayAuthBypassPaths };
@@ -15,7 +15,7 @@ function isMattermostBypassPath(path) {
15
15
  return path === DEFAULT_SLASH_CALLBACK_PATH || path.startsWith("/api/channels/mattermost/");
16
16
  }
17
17
  function collectMattermostSlashCallbackPaths(raw) {
18
- const paths = new Set([normalizeCallbackPath(raw?.callbackPath)]);
18
+ const paths = /* @__PURE__ */ new Set([normalizeCallbackPath(raw?.callbackPath)]);
19
19
  const callbackUrl = readTrimmedString(raw?.callbackUrl);
20
20
  if (callbackUrl) try {
21
21
  const pathname = new URL(callbackUrl).pathname;
@@ -1,2 +1,2 @@
1
- import { i as registerSlashCommandRoute } from "./slash-state-D1lza2ZZ.js";
1
+ import { i as registerSlashCommandRoute } from "./slash-state-BfOSlkmn.js";
2
2
  export { registerSlashCommandRoute };
@@ -1,5 +1,5 @@
1
1
  import { a as normalizeMattermostAllowList, b as readRequestBodyWithLimit, d as createChannelMessageReplyPipeline, g as loadOutboundMediaFromUrl, l as buildModelsProviderData, m as isTrustedProxyAddress, p as isRequestBodyLimitError, t as authorizeMattermostCommandInvocation, v as logTypingFailure, w as resolveClientIp } from "./monitor-auth-BiDuyvOc.js";
2
- import { b as updateMattermostPost, c as createMattermostPost, d as fetchMattermostChannelByName, f as fetchMattermostMe, g as normalizeMattermostBaseUrl, h as fetchMattermostUserTeams, m as fetchMattermostUserByUsername, o as createMattermostClient, p as fetchMattermostUser, r as resolveMattermostAccount, s as createMattermostDirectChannelWithRetry, u as fetchMattermostChannel, v as resolveMattermostReplyDeliveryBarrierTimeoutMs, x as uploadMattermostFile, y as sendMattermostTyping } from "./accounts-Bt60MyHp.js";
2
+ import { b as updateMattermostPost, c as createMattermostPost, d as fetchMattermostChannelByName, f as fetchMattermostMe, g as normalizeMattermostBaseUrl, h as fetchMattermostUserTeams, m as fetchMattermostUserByUsername, o as createMattermostClient, p as fetchMattermostUser, r as resolveMattermostAccount, s as createMattermostDirectChannelWithRetry, u as fetchMattermostChannel, v as resolveMattermostReplyDeliveryBarrierTimeoutMs, x as uploadMattermostFile, y as sendMattermostTyping } from "./accounts-ITTlduDO.js";
3
3
  import { t as getMattermostRuntime } from "./runtime-CNB4YGqJ.js";
4
4
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeStringifiedOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
5
5
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
@@ -16,6 +16,19 @@ import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
16
16
  import { createHash, createHmac } from "node:crypto";
17
17
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
18
18
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
19
+ const MATTERMOST_COMMAND_DESCRIPTION_MAX_BYTES = 128;
20
+ function truncateMattermostCommandDescription(description) {
21
+ if (Buffer.byteLength(description, "utf8") <= MATTERMOST_COMMAND_DESCRIPTION_MAX_BYTES) return description;
22
+ let bytes = 0;
23
+ let end = 0;
24
+ for (const char of description) {
25
+ const charBytes = Buffer.byteLength(char, "utf8");
26
+ if (bytes + charBytes > MATTERMOST_COMMAND_DESCRIPTION_MAX_BYTES) break;
27
+ bytes += charBytes;
28
+ end += char.length;
29
+ }
30
+ return description.slice(0, end);
31
+ }
19
32
  /**
20
33
  * Built-in OpenClaw commands to register as native slash commands.
21
34
  * These mirror the text-based commands already handled by the gateway.
@@ -142,6 +155,7 @@ async function registerSlashCommands(params) {
142
155
  }
143
156
  const registered = [];
144
157
  for (const spec of commands) {
158
+ const description = truncateMattermostCommandDescription(spec.description);
145
159
  const existingForTrigger = existingByTrigger.get(spec.trigger) ?? [];
146
160
  const ownedCommands = existingForTrigger.filter((cmd) => cmd.creator_id?.trim() === normalizedCreatorUserId);
147
161
  const foreignCommands = existingForTrigger.filter((cmd) => cmd.creator_id?.trim() !== normalizedCreatorUserId);
@@ -173,9 +187,9 @@ async function registerSlashCommands(params) {
173
187
  trigger: spec.trigger,
174
188
  method: "P",
175
189
  url: callbackUrl,
176
- description: spec.description,
190
+ description,
177
191
  auto_complete: spec.autoComplete,
178
- auto_complete_desc: spec.description,
192
+ auto_complete_desc: description,
179
193
  auto_complete_hint: spec.autoCompleteHint
180
194
  });
181
195
  registered.push({
@@ -204,9 +218,9 @@ async function registerSlashCommands(params) {
204
218
  trigger: spec.trigger,
205
219
  method: "P",
206
220
  url: callbackUrl,
207
- description: spec.description,
221
+ description,
208
222
  auto_complete: spec.autoComplete,
209
- auto_complete_desc: spec.description,
223
+ auto_complete_desc: description,
210
224
  auto_complete_hint: spec.autoCompleteHint
211
225
  });
212
226
  log?.(`mattermost: registered command /${spec.trigger} (id=${created.id})`);
@@ -1451,7 +1465,7 @@ const COMMAND_VALIDATION_LOOKUP_RATE_LIMIT_MAX_KEYS = 2e3;
1451
1465
  const commandLookupInflight = /* @__PURE__ */ new Map();
1452
1466
  const commandValidationFailureCache = /* @__PURE__ */ new Map();
1453
1467
  const commandValidationLookupRateLimit = /* @__PURE__ */ new Map();
1454
- const SECRET_LOG_KEYS = new Set([
1468
+ const SECRET_LOG_KEYS = /* @__PURE__ */ new Set([
1455
1469
  "access_token",
1456
1470
  "authorization",
1457
1471
  "bottoken",
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@openclaw/mattermost",
3
- "version": "2026.7.1-beta.1",
3
+ "version": "2026.7.1-beta.4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/mattermost",
9
- "version": "2026.7.1-beta.1",
9
+ "version": "2026.7.1-beta.4",
10
10
  "dependencies": {
11
11
  "ws": "8.21.0",
12
12
  "zod": "4.4.3"
13
13
  },
14
14
  "peerDependencies": {
15
- "openclaw": ">=2026.7.1-beta.1"
15
+ "openclaw": ">=2026.7.1-beta.4"
16
16
  },
17
17
  "peerDependenciesMeta": {
18
18
  "openclaw": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/mattermost",
3
- "version": "2026.7.1-beta.1",
3
+ "version": "2026.7.1-beta.4",
4
4
  "description": "OpenClaw Mattermost channel plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "zod": "4.4.3"
13
13
  },
14
14
  "peerDependencies": {
15
- "openclaw": ">=2026.7.1-beta.1"
15
+ "openclaw": ">=2026.7.1-beta.4"
16
16
  },
17
17
  "peerDependenciesMeta": {
18
18
  "openclaw": {
@@ -41,10 +41,10 @@
41
41
  "allowInvalidConfigRecovery": true
42
42
  },
43
43
  "compat": {
44
- "pluginApi": ">=2026.7.1-beta.1"
44
+ "pluginApi": ">=2026.7.1-beta.4"
45
45
  },
46
46
  "build": {
47
- "openclawVersion": "2026.7.1-beta.1",
47
+ "openclawVersion": "2026.7.1-beta.4",
48
48
  "bundledDist": false
49
49
  },
50
50
  "release": {