@openclaw/msteams 2026.9.5 → 2026.9.7

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.
Files changed (33) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{adapter.runtime-ChuVK6k_.cjs → adapter.runtime-BiWeMKXE.cjs} +24 -30
  3. package/dist/.setup/{approval-card-CPNH_q3P.cjs → approval-card-DWPDItvq.cjs} +6 -3
  4. package/dist/.setup/{approval-handler.runtime-DDxGPJDz.cjs → approval-handler.runtime-D1s7UR3U.cjs} +4 -4
  5. package/dist/.setup/bot-framework-service-url-BUhTe8F3.cjs +55 -0
  6. package/dist/.setup/{channel-Dzpbbht8.cjs → channel-ByzS7QJ0.cjs} +338 -220
  7. package/dist/.setup/{channel.runtime-TE49QvFv.cjs → channel.runtime-Baz8XDFs.cjs} +47 -144
  8. package/dist/.setup/{channel.setup-BVDfgdCc.cjs → channel.setup-DL8lcWT_.cjs} +6 -6
  9. package/dist/.setup/{config-schema-D22Lr1Qk.cjs → config-schema-0KoBzb0t.cjs} +24 -38
  10. package/dist/.setup/{messenger-BR1l4zw-.cjs → conversation-store-state-B7JuyZTm.cjs} +697 -297
  11. package/dist/.setup/{src-CpKfpP1m.cjs → monitor-BJ7IyH4y.cjs} +440 -663
  12. package/dist/.setup/{oauth-C6m7dvHj.cjs → oauth-DQjOnJ4l.cjs} +1 -1
  13. package/dist/.setup/{reaction-types-C7RA7Wxt.cjs → reaction-types-CQ4oSUe7.cjs} +2 -6
  14. package/dist/.setup/{resolve-allowlist-CHzaaWiC.cjs → resolve-allowlist-Pl_NQFYH.cjs} +55 -312
  15. package/dist/.setup/{rolldown-runtime-VH7oDXx4.cjs → rolldown-runtime-BloeesfJ.cjs} +22 -0
  16. package/dist/.setup/{send-D8ATH4QI.cjs → send-VUM7Sryb.cjs} +47 -97
  17. package/dist/.setup/{setup-plugin-api-DpiaA8z1.cjs → setup-plugin-api-Dyf8kF-l.cjs} +1 -1
  18. package/dist/.setup/{thread-session-CXgHK-yi.cjs → thread-session--rw3BTal.cjs} +2 -5
  19. package/dist/api.cjs +2 -2
  20. package/dist/channel-config-api.cjs +1 -1
  21. package/dist/channel-plugin-api.cjs +1 -1
  22. package/dist/configured-state.cjs +0 -1
  23. package/dist/directory-contract-api.cjs +1 -1
  24. package/dist/doctor-contract-api.cjs +201 -371
  25. package/dist/qa-runner-api.cjs +1 -1
  26. package/dist/runtime-api.cjs +0 -6
  27. package/dist/setup-entry.cjs +1 -1
  28. package/dist/setup-plugin-api.cjs +1 -1
  29. package/openclaw.plugin.json +46 -5
  30. package/package.json +10 -10
  31. package/dist/.setup/polls-BJ4-4uZm.cjs +0 -668
  32. package/dist/.setup/secret-input-C65t6kjM.cjs +0 -1
  33. package/dist/.setup/sso-token-store-YYLHXgFH.cjs +0 -111
@@ -1,10 +1,11 @@
1
1
  require("../runtime-api.cjs");
2
- const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
3
- const require_channel = require("./channel-Dzpbbht8.cjs");
4
- const require_channel_setup = require("./channel.setup-BVDfgdCc.cjs");
5
- const require_polls = require("./polls-BJ4-4uZm.cjs");
6
- const require_send = require("./send-D8ATH4QI.cjs");
7
- const require_reaction_types = require("./reaction-types-C7RA7Wxt.cjs");
2
+ const require_resolve_allowlist = require("./resolve-allowlist-Pl_NQFYH.cjs");
3
+ const require_delegated_state = require("./delegated-state-u-ywZyZT.cjs");
4
+ const require_channel = require("./channel-ByzS7QJ0.cjs");
5
+ const require_channel_setup = require("./channel.setup-DL8lcWT_.cjs");
6
+ const require_conversation_store_state = require("./conversation-store-state-B7JuyZTm.cjs");
7
+ const require_send = require("./send-VUM7Sryb.cjs");
8
+ const require_reaction_types = require("./reaction-types-CQ4oSUe7.cjs");
8
9
  let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
9
10
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
10
11
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
@@ -22,19 +23,19 @@ async function listMSTeamsDirectoryPeersLive(params) {
22
23
  token,
23
24
  query,
24
25
  top: limit
25
- })).map((user) => {
26
+ })).flatMap((user) => {
26
27
  const id = user.id?.trim();
27
- if (!id) return null;
28
+ if (!id) return [];
28
29
  const name = user.displayName?.trim();
29
30
  const handle = user.userPrincipalName?.trim() || user.mail?.trim();
30
- return {
31
+ return [{
31
32
  kind: "user",
32
33
  id: `user:${id}`,
33
34
  name: name || void 0,
34
35
  handle: handle ? `@${handle}` : void 0,
35
36
  raw: user
36
- };
37
- }).filter(Boolean);
37
+ }];
38
+ });
38
39
  }
39
40
  async function listMSTeamsDirectoryGroupsLive(params) {
40
41
  const rawQuery = require_resolve_allowlist.normalizeQuery(params.query);
@@ -78,20 +79,8 @@ async function listMSTeamsDirectoryGroupsLive(params) {
78
79
  }
79
80
  //#endregion
80
81
  //#region extensions/msteams/src/graph-messages.ts
81
- /**
82
- * Resolve the Graph API path prefix for a conversation.
83
- * If `to` contains "/" it's a `teamId/channelId` (channel path),
84
- * otherwise it's a chat ID.
85
- */
86
- /**
87
- * Strip common target prefixes (`conversation:`, `user:`) so raw
88
- * conversation IDs can be used directly in Graph paths.
89
- */
90
82
  function stripTargetPrefix(raw) {
91
- const trimmed = raw.trim();
92
- if (/^conversation:/i.test(trimmed)) return trimmed.slice(13).trim();
93
- if (/^user:/i.test(trimmed)) return trimmed.slice(5).trim();
94
- return trimmed;
83
+ return raw.trim().replace(/^(conversation|user):/i, "").trim();
95
84
  }
96
85
  /**
97
86
  * Resolve a target to a Graph-compatible conversation ID.
@@ -104,7 +93,7 @@ async function resolveGraphConversationId(to) {
104
93
  const isUserTarget = /^user:/i.test(trimmed);
105
94
  const cleaned = stripTargetPrefix(trimmed);
106
95
  if (!isUserTarget) return cleaned;
107
- const found = await require_polls.createMSTeamsConversationStoreState().findPreferredDmByUserId(cleaned);
96
+ const found = await require_conversation_store_state.createMSTeamsConversationStoreState().findPreferredDmByUserId(cleaned);
108
97
  if (!found) throw new Error(`No conversation found for user:${cleaned}. The bot must receive a message from this user before Graph API operations work.`);
109
98
  if (found.conversationId.startsWith("19:")) return found.conversationId;
110
99
  throw new Error(`Conversation for user:${cleaned} uses a Bot Framework ID (${found.conversationId}) that Graph API does not accept. Use a Graph-native conversation:19:... target when available.`);
@@ -128,9 +117,6 @@ function resolveConversationPath(to) {
128
117
  chatId: cleaned
129
118
  };
130
119
  }
131
- /**
132
- * Retrieve a single message by ID from a chat or channel via Graph API.
133
- */
134
120
  async function getMessageMSTeams(params) {
135
121
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
136
122
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
@@ -146,17 +132,6 @@ async function getMessageMSTeams(params) {
146
132
  createdAt: msg.createdDateTime
147
133
  };
148
134
  }
149
- /**
150
- * Pin a message in a chat conversation via Graph API.
151
- *
152
- * Chat pinning uses the v1.0 endpoint: `POST /chats/{chatId}/pinnedMessages`.
153
- *
154
- * Channel pinning uses `POST /teams/{teamId}/channels/{channelId}/pinnedMessages`.
155
- * **Note:** The channel pin endpoint may require the Graph beta API or specific
156
- * tenant-level permissions. As of March 2026, general availability is not
157
- * confirmed for all tenants. If the call returns 404 or 403, the endpoint may
158
- * not be enabled for the target tenant.
159
- */
160
135
  async function pinMessageMSTeams(params) {
161
136
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
162
137
  const conversationId = await resolveGraphConversationId(params.to);
@@ -173,14 +148,6 @@ async function pinMessageMSTeams(params) {
173
148
  })).id
174
149
  };
175
150
  }
176
- /**
177
- * Unpin a message in a chat conversation via Graph API.
178
- * `pinnedMessageId` is the pinned-message resource ID (from pin or list-pins),
179
- * not the underlying chat message ID.
180
- *
181
- * Channel unpin uses `DELETE /teams/{teamId}/channels/{channelId}/pinnedMessages/{id}`.
182
- * See the note on {@link pinMessageMSTeams} regarding beta/GA status.
183
- */
184
151
  async function unpinMessageMSTeams(params) {
185
152
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
186
153
  const conv = resolveConversationPath(await resolveGraphConversationId(params.to));
@@ -192,15 +159,7 @@ async function unpinMessageMSTeams(params) {
192
159
  });
193
160
  return { ok: true };
194
161
  }
195
- /** Maximum number of pagination pages to follow to avoid unbounded loops. */
196
162
  const LIST_PINS_MAX_PAGES = 10;
197
- /**
198
- * List all pinned messages in a chat conversation via Graph API.
199
- * Follows `@odata.nextLink` pagination to collect the full pin set.
200
- *
201
- * Channel list-pins uses the same endpoint pattern as channel pin/unpin.
202
- * See the note on {@link pinMessageMSTeams} regarding beta/GA status.
203
- */
204
163
  async function listPinsMSTeams(params) {
205
164
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
206
165
  const conv = resolveConversationPath(await resolveGraphConversationId(params.to));
@@ -229,47 +188,24 @@ async function listPinsMSTeams(params) {
229
188
  }
230
189
  return { pins: allPins };
231
190
  }
232
- /**
233
- * Add an emoji reaction to a message via Graph API (beta).
234
- *
235
- * Writes (setReaction) require a Delegated token, so we pass
236
- * `preferDelegated: true`. The resolver falls back to the app-only token when
237
- * delegated auth is not configured, preserving today's behavior while letting
238
- * delegated-auth-enabled deployments hit the user-scoped endpoint.
239
- */
240
- async function reactMessageMSTeams(params) {
191
+ async function mutateMessageReaction(params, operation) {
241
192
  const reactionType = require_reaction_types.resolveMSTeamsReactionEmoji(params.reactionType);
242
193
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg, { preferDelegated: true });
243
194
  const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
244
- const path = `${basePath}/messages/${encodeURIComponent(params.messageId)}/setReaction`;
245
195
  await require_resolve_allowlist.mutateGraphJson({
246
196
  token,
247
- path,
197
+ path: `${basePath}/messages/${encodeURIComponent(params.messageId)}/${operation}`,
248
198
  method: "POST",
249
199
  body: { reactionType },
250
200
  beta: true
251
201
  });
252
202
  return { ok: true };
253
203
  }
254
- /**
255
- * Remove an emoji reaction from a message via Graph API (beta).
256
- *
257
- * Writes (unsetReaction) require a Delegated token, so we pass
258
- * `preferDelegated: true`. See `reactMessageMSTeams` for fallback rules.
259
- */
260
- async function unreactMessageMSTeams(params) {
261
- const reactionType = require_reaction_types.resolveMSTeamsReactionEmoji(params.reactionType);
262
- const token = await require_resolve_allowlist.resolveGraphToken(params.cfg, { preferDelegated: true });
263
- const { basePath } = resolveConversationPath(await resolveGraphConversationId(params.to));
264
- const path = `${basePath}/messages/${encodeURIComponent(params.messageId)}/unsetReaction`;
265
- await require_resolve_allowlist.mutateGraphJson({
266
- token,
267
- path,
268
- method: "POST",
269
- body: { reactionType },
270
- beta: true
271
- });
272
- return { ok: true };
204
+ function reactMessageMSTeams(params) {
205
+ return mutateMessageReaction(params, "setReaction");
206
+ }
207
+ function unreactMessageMSTeams(params) {
208
+ return mutateMessageReaction(params, "unsetReaction");
273
209
  }
274
210
  /**
275
211
  * List reactions on a message, grouped by type.
@@ -375,11 +311,10 @@ const MAX_CONVERSATION_MEMBER_PAGES = 100;
375
311
  async function findMSTeamsConversationMember(params) {
376
312
  const conversationId = await resolveGraphConversationId(params.to);
377
313
  const conversation = resolveConversationPath(conversationId);
378
- const collection = conversation.kind === "channel" && params.includeIndirectChannelMembers ? "allMembers" : "members";
379
314
  const userId = params.userId.trim().toLowerCase();
380
315
  const result = await require_resolve_allowlist.fetchAllGraphPages({
381
316
  token: params.token,
382
- path: `${conversation.basePath}/${collection}`,
317
+ path: `${conversation.basePath}/members`,
383
318
  maxPages: MAX_CONVERSATION_MEMBER_PAGES,
384
319
  collectItems: false,
385
320
  findOne: (candidate) => candidate.userId?.trim().toLowerCase() === userId || candidate.email?.trim().toLowerCase() === userId
@@ -403,9 +338,6 @@ function resolveConversationMemberRoles(role, kind) {
403
338
  if (kind === "chat") return ["owner"];
404
339
  return normalized === "owner" ? ["owner"] : [];
405
340
  }
406
- /**
407
- * Add a user to a chat or channel via Graph API.
408
- */
409
341
  async function addParticipantMSTeams(params) {
410
342
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
411
343
  const conversationId = await resolveGraphConversationId(params.to);
@@ -448,9 +380,6 @@ async function removeParticipantMSTeams(params) {
448
380
  chatId: conversationId
449
381
  } };
450
382
  }
451
- /**
452
- * Rename a chat (topic) or channel (displayName) via Graph API.
453
- */
454
383
  async function renameGroupMSTeams(params) {
455
384
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
456
385
  const conversationId = await resolveGraphConversationId(params.to);
@@ -522,11 +451,6 @@ async function getMemberInfoMSTeams(params) {
522
451
  }
523
452
  //#endregion
524
453
  //#region extensions/msteams/src/graph-teams.ts
525
- /**
526
- * List channels in a team via Graph API.
527
- * Returns id, displayName, description, and membershipType for each channel.
528
- * Follows @odata.nextLink for paginated results (up to 10 pages).
529
- */
530
454
  async function listChannelsMSTeams(params) {
531
455
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
532
456
  const result = await require_resolve_allowlist.fetchAllGraphPages({
@@ -544,10 +468,6 @@ async function listChannelsMSTeams(params) {
544
468
  truncated: result.truncated
545
469
  };
546
470
  }
547
- /**
548
- * Get detailed information about a single channel in a team via Graph API.
549
- * Returns id, displayName, description, membershipType, webUrl, and createdDateTime.
550
- */
551
471
  async function getChannelInfoMSTeams(params) {
552
472
  const token = await require_resolve_allowlist.resolveGraphToken(params.cfg);
553
473
  const path = `/teams/${encodeURIComponent(params.teamId)}/channels/${encodeURIComponent(params.channelId)}?$select=id,displayName,description,membershipType,webUrl,createdDateTime`;
@@ -597,7 +517,7 @@ function resolveMSTeamsThreadTarget(to, threadId) {
597
517
  if (!normalizedThreadId || /(?:^|;)messageid=/iu.test(to) || !isConversationTarget) return to;
598
518
  return `${to};messageid=${normalizedThreadId}`;
599
519
  }
600
- function resolveMSTeamsTextSend(params) {
520
+ function resolveMSTeamsSend(params) {
601
521
  return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text, opts) => require_send.sendMessageMSTeams({
602
522
  cfg: params.cfg,
603
523
  to,
@@ -605,13 +525,19 @@ function resolveMSTeamsTextSend(params) {
605
525
  ...opts
606
526
  }));
607
527
  }
608
- function resolveMSTeamsMediaSend(params) {
609
- return (0, openclaw_plugin_sdk_channel_outbound.resolveOutboundSendDep)(params.deps, "msteams") ?? ((to, text, opts) => require_send.sendMessageMSTeams({
610
- cfg: params.cfg,
611
- to,
612
- text,
613
- ...opts
614
- }));
528
+ async function sendMSTeamsOutbound(ctx, includeMedia) {
529
+ const send = resolveMSTeamsSend(ctx);
530
+ return toMSTeamsOutboundResult(await sendWithDeliveryResults((report) => send(resolveMSTeamsThreadTarget(ctx.to, ctx.threadId), ctx.text, {
531
+ ...includeMedia ? {
532
+ mediaUrl: ctx.mediaUrl,
533
+ mediaAccess: ctx.mediaAccess,
534
+ mediaLocalRoots: ctx.mediaLocalRoots,
535
+ mediaReadFile: ctx.mediaReadFile
536
+ } : {},
537
+ assertDirectAdapterHandoff: ctx.assertDirectAdapterHandoff,
538
+ onPlatformSendDispatch: ctx.onPlatformSendDispatch,
539
+ onDeliveryResult: report
540
+ }), ctx.onDeliveryResult));
615
541
  }
616
542
  const msteamsOutbound = {
617
543
  deliveryMode: "direct",
@@ -667,7 +593,7 @@ const msteamsOutbound = {
667
593
  mediaUrl: payload.mediaUrl ?? mediaUrl
668
594
  }));
669
595
  if (mediaUrls.length > 0) {
670
- const send = resolveMSTeamsMediaSend({
596
+ const send = resolveMSTeamsSend({
671
597
  cfg,
672
598
  deps
673
599
  });
@@ -686,7 +612,7 @@ const msteamsOutbound = {
686
612
  if (result) return (0, openclaw_plugin_sdk_channel_send_result.attachChannelToResult)("msteams", toMSTeamsOutboundResult(result));
687
613
  }
688
614
  if (text.trim()) {
689
- const send = resolveMSTeamsTextSend({
615
+ const send = resolveMSTeamsSend({
690
616
  cfg,
691
617
  deps
692
618
  });
@@ -702,42 +628,20 @@ const msteamsOutbound = {
702
628
  },
703
629
  ...(0, openclaw_plugin_sdk_channel_send_result.createAttachedChannelResultAdapter)({
704
630
  channel: "msteams",
705
- sendText: async ({ cfg, to, text, deps, threadId, assertDirectAdapterHandoff, onPlatformSendDispatch, onDeliveryResult }) => {
706
- const send = resolveMSTeamsTextSend({
707
- cfg,
708
- deps
709
- });
710
- return toMSTeamsOutboundResult(await sendWithDeliveryResults((report) => send(resolveMSTeamsThreadTarget(to, threadId), text, {
711
- assertDirectAdapterHandoff,
712
- onPlatformSendDispatch,
713
- onDeliveryResult: report
714
- }), onDeliveryResult));
715
- },
716
- sendMedia: async ({ cfg, to, text, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, deps, threadId, assertDirectAdapterHandoff, onPlatformSendDispatch, onDeliveryResult }) => {
717
- const send = resolveMSTeamsMediaSend({
718
- cfg,
719
- deps
720
- });
721
- return toMSTeamsOutboundResult(await sendWithDeliveryResults((report) => send(resolveMSTeamsThreadTarget(to, threadId), text, {
722
- mediaUrl,
723
- mediaAccess,
724
- mediaLocalRoots,
725
- mediaReadFile,
726
- assertDirectAdapterHandoff,
727
- onPlatformSendDispatch,
728
- onDeliveryResult: report
729
- }), onDeliveryResult));
730
- },
731
- sendPoll: async ({ cfg, to, poll, threadId }) => {
631
+ sendText: (ctx) => sendMSTeamsOutbound(ctx, false),
632
+ sendMedia: (ctx) => sendMSTeamsOutbound(ctx, true),
633
+ sendPoll: async ({ cfg, to, poll, threadId, assertDirectAdapterHandoff, onPlatformSendDispatch }) => {
732
634
  const maxSelections = poll.maxSelections ?? 1;
733
635
  const result = await require_send.sendPollMSTeams({
734
636
  cfg,
735
637
  to: resolveMSTeamsThreadTarget(to, threadId),
736
638
  question: poll.question,
737
639
  options: poll.options,
738
- maxSelections
640
+ maxSelections,
641
+ assertDirectAdapterHandoff,
642
+ onPlatformSendDispatch
739
643
  });
740
- await require_polls.createMSTeamsPollStoreState().createPoll({
644
+ await require_conversation_store_state.createMSTeamsPollStoreState().createPoll({
741
645
  id: result.pollId,
742
646
  question: poll.question,
743
647
  options: poll.options,
@@ -791,11 +695,10 @@ async function probeMSTeams(cfg) {
791
695
  })) throw new Error("Failed to acquire bot token");
792
696
  let graph;
793
697
  try {
794
- const graphTokenValue = await require_resolve_allowlist.withMSTeamsRequestDeadline({
698
+ const accessToken = await require_resolve_allowlist.withMSTeamsRequestDeadline({
795
699
  label: "MS Teams Graph probe token",
796
700
  work: () => tokenProvider.getAccessToken("https://graph.microsoft.com")
797
701
  });
798
- const accessToken = require_resolve_allowlist.readAccessToken(graphTokenValue);
799
702
  const payload = accessToken ? decodeJwtPayload(accessToken) : null;
800
703
  graph = {
801
704
  ok: true,
@@ -810,7 +713,7 @@ async function probeMSTeams(cfg) {
810
713
  }
811
714
  let delegatedAuth;
812
715
  if (cfg?.delegatedAuth?.enabled) try {
813
- const tokens = await require_resolve_allowlist.loadDelegatedTokens();
716
+ const tokens = await require_delegated_state.loadMSTeamsDelegatedTokens();
814
717
  if (tokens) {
815
718
  const isExpired = !(0, openclaw_plugin_sdk_number_runtime.isFutureDateTimestampMs)(tokens.expiresAt);
816
719
  delegatedAuth = {
@@ -1,18 +1,18 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-CHzaaWiC.cjs");
2
- require("./secret-input-C65t6kjM.cjs");
3
- const require_config_schema = require("./config-schema-D22Lr1Qk.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-Pl_NQFYH.cjs");
2
+ const require_delegated_state = require("./delegated-state-u-ywZyZT.cjs");
3
+ const require_config_schema = require("./config-schema-0KoBzb0t.cjs");
4
4
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
5
5
  let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
6
6
  let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
7
7
  let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
8
8
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
9
+ let openclaw_plugin_sdk_secret_input = require("openclaw/plugin-sdk/secret-input");
9
10
  let openclaw_plugin_sdk_channel_config_helpers = require("openclaw/plugin-sdk/channel-config-helpers");
10
11
  let openclaw_plugin_sdk_secret_file_runtime = require("openclaw/plugin-sdk/secret-file-runtime");
11
12
  let openclaw_plugin_sdk_channel_setup = require("openclaw/plugin-sdk/channel-setup");
12
13
  let openclaw_plugin_sdk_setup = require("openclaw/plugin-sdk/setup");
13
14
  let openclaw_plugin_sdk_setup_tools = require("openclaw/plugin-sdk/setup-tools");
14
15
  let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
15
- let openclaw_plugin_sdk_secret_input = require("openclaw/plugin-sdk/secret-input");
16
16
  //#region extensions/msteams/src/channel-config.ts
17
17
  const msteamsMeta = {
18
18
  id: "msteams",
@@ -475,7 +475,7 @@ const msteamsSetupWizard = {
475
475
  };
476
476
  let oauthModule;
477
477
  try {
478
- oauthModule = await Promise.resolve().then(() => require("./oauth-C6m7dvHj.cjs"));
478
+ oauthModule = await Promise.resolve().then(() => require("./oauth-DQjOnJ4l.cjs"));
479
479
  } catch (err) {
480
480
  await noteDelegatedAuthFailure(err);
481
481
  return {
@@ -515,7 +515,7 @@ const msteamsSetupWizard = {
515
515
  progress.stop();
516
516
  throw err;
517
517
  }
518
- await require_resolve_allowlist.saveDelegatedTokens(tokens);
518
+ await require_delegated_state.saveMSTeamsDelegatedTokens(tokens);
519
519
  progress.stop(t("wizard.msteams.delegatedAuthConfigured"));
520
520
  }
521
521
  }
@@ -1,4 +1,6 @@
1
+ const require_bot_framework_service_url = require("./bot-framework-service-url-BUhTe8F3.cjs");
1
2
  let openclaw_plugin_sdk_channel_core = require("openclaw/plugin-sdk/channel-core");
3
+ let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
2
4
  let openclaw_plugin_sdk_secret_input = require("openclaw/plugin-sdk/secret-input");
3
5
  let openclaw_plugin_sdk_channel_config_schema = require("openclaw/plugin-sdk/channel-config-schema");
4
6
  let zod = require("zod");
@@ -24,6 +26,18 @@ const msTeamsChannelConfigUiHints = {
24
26
  label: "MS Teams Graph Media Fallback",
25
27
  help: "Query Microsoft Graph for unresolved channel or group-chat HTML media. Adds one lookup per matching message when enabled (default: false)."
26
28
  },
29
+ requireMentionInBotThreads: {
30
+ label: "Require Mentions in Bot Threads",
31
+ help: "Override mention requirements for channel threads rooted at this bot's tracked messages. Unset preserves existing behavior. Channel overrides win over team and global values. Ownership tracking lasts up to 24 hours."
32
+ },
33
+ "teams.*.requireMentionInBotThreads": {
34
+ label: "Team Bot Thread Mentions",
35
+ help: "Override mention requirements for this bot's channel threads in this team. Unset inherits the global value."
36
+ },
37
+ "teams.*.channels.*.requireMentionInBotThreads": {
38
+ label: "Channel Bot Thread Mentions",
39
+ help: "Override mention requirements for this bot's threads in this channel. Unset inherits the team or global value."
40
+ },
27
41
  ...(0, openclaw_plugin_sdk_channel_core.createChannelConfigUiHints)({
28
42
  channelLabel: "MS Teams",
29
43
  streaming: { "": {
@@ -42,43 +56,14 @@ const SecretInputSchema = (0, openclaw_plugin_sdk_secret_input.buildSecretInputS
42
56
  const ToolPolicyBySenderSchema = zod.z.record(zod.z.string(), openclaw_plugin_sdk_channel_config_schema.ToolPolicySchema).optional();
43
57
  const MSTeamsChannelSchema = zod.z.object({
44
58
  requireMention: zod.z.boolean().optional(),
59
+ requireMentionInBotThreads: zod.z.boolean().optional(),
45
60
  tools: openclaw_plugin_sdk_channel_config_schema.ToolPolicySchema,
46
61
  toolsBySender: ToolPolicyBySenderSchema,
47
62
  replyStyle: openclaw_plugin_sdk_channel_config_schema.MSTeamsReplyStyleSchema.optional()
48
63
  }).strict();
49
- const MSTeamsTeamSchema = zod.z.object({
50
- requireMention: zod.z.boolean().optional(),
51
- tools: openclaw_plugin_sdk_channel_config_schema.ToolPolicySchema,
52
- toolsBySender: ToolPolicyBySenderSchema,
53
- replyStyle: openclaw_plugin_sdk_channel_config_schema.MSTeamsReplyStyleSchema.optional(),
54
- channels: zod.z.record(zod.z.string(), MSTeamsChannelSchema.optional()).optional()
55
- }).strict();
56
- const MSTEAMS_SERVICE_URL_HOST_ALLOWLIST = [
57
- "smba.trafficmanager.net",
58
- "smba.infra.gcc.teams.microsoft.com",
59
- "smba.infra.gov.teams.microsoft.us",
60
- "smba.infra.dod.teams.microsoft.us",
61
- "botframework.azure.cn"
62
- ];
63
- function isAllowedMSTeamsServiceUrl(value) {
64
- try {
65
- const parsed = new URL(value.trim());
66
- if (parsed.protocol !== "https:") return false;
67
- const host = parsed.hostname.toLowerCase();
68
- return MSTEAMS_SERVICE_URL_HOST_ALLOWLIST.some((allowed) => host === allowed || host.endsWith(`.${allowed}`));
69
- } catch {
70
- return false;
71
- }
72
- }
64
+ const MSTeamsTeamSchema = MSTeamsChannelSchema.extend({ channels: zod.z.record(zod.z.string(), MSTeamsChannelSchema.optional()).optional() });
73
65
  function isAzureChinaBotFrameworkServiceUrl(value) {
74
- try {
75
- const parsed = new URL(value.trim());
76
- if (parsed.protocol !== "https:") return false;
77
- const host = parsed.hostname.toLowerCase();
78
- return host === "botframework.azure.cn" || host.endsWith(".botframework.azure.cn");
79
- } catch {
80
- return false;
81
- }
66
+ return (0, openclaw_plugin_sdk_ssrf_policy.isHttpsUrlAllowedByHostnameSuffixAllowlist)(value.trim(), ["botframework.azure.cn"]);
82
67
  }
83
68
  const { accountShape, rootPolicyShape } = (0, openclaw_plugin_sdk_channel_config_schema.buildChannelAccountSchemaParts)({
84
69
  omit: [
@@ -103,24 +88,25 @@ const MSTeamsConfigSchema = zod.z.object({
103
88
  "USGovDoD",
104
89
  "China"
105
90
  ]).optional(),
106
- serviceUrl: zod.z.string().url().refine(isAllowedMSTeamsServiceUrl, { message: "channels.msteams.serviceUrl must use a supported Microsoft Teams Bot Connector host" }).optional(),
91
+ serviceUrl: zod.z.string().url().refine(require_bot_framework_service_url.isAllowedBotFrameworkServiceUrl, { message: "channels.msteams.serviceUrl must use a supported Microsoft Teams Bot Connector host" }).optional(),
107
92
  authType: zod.z.enum(["secret", "federated"]).optional(),
108
93
  certificatePath: zod.z.string().optional(),
109
94
  certificateThumbprint: zod.z.string().optional(),
110
95
  useManagedIdentity: zod.z.boolean().optional(),
111
96
  managedIdentityClientId: zod.z.string().optional(),
112
- webhook: zod.z.object({
113
- port: zod.z.number().int().positive().optional(),
114
- path: zod.z.string().optional()
115
- }).strict().optional(),
97
+ webhook: zod.z.object({ path: zod.z.string().optional() }).strict().optional(),
98
+ legacyWebhook: zod.z.union([zod.z.literal(false), zod.z.object({
99
+ port: zod.z.number().int().min(1).max(65535),
100
+ host: zod.z.string().optional()
101
+ }).strict()]).optional(),
116
102
  typingIndicator: zod.z.boolean().optional(),
117
103
  mediaAllowHosts: zod.z.array(zod.z.string()).optional(),
118
104
  mediaAuthAllowHosts: zod.z.array(zod.z.string()).optional(),
119
105
  graphMediaFallback: zod.z.boolean().optional(),
120
106
  requireMention: zod.z.boolean().optional(),
107
+ requireMentionInBotThreads: zod.z.boolean().optional(),
121
108
  replyStyle: openclaw_plugin_sdk_channel_config_schema.MSTeamsReplyStyleSchema.optional(),
122
109
  teams: zod.z.record(zod.z.string(), MSTeamsTeamSchema.optional()).optional(),
123
- /** Max inbound and outbound media size in MB (default: 100MB). */
124
110
  /** SharePoint site ID for file uploads in group chats/channels (e.g., "contoso.sharepoint.com,guid1,guid2") */
125
111
  sharePointSiteId: zod.z.string().optional(),
126
112
  welcomeCard: zod.z.boolean().optional(),