@openclaw/msteams 2026.7.2-beta.7 → 2026.8.1-beta.3

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.
@@ -1,8 +1,7 @@
1
1
  require("./runtime-api.cjs");
2
- const require_resolve_allowlist = require("./resolve-allowlist-CEj9sABO.cjs");
3
- const require_setup_surface = require("./setup-surface-ByWjaXEn.cjs");
4
- const require_config_schema = require("./config-schema-C4CszdDi.cjs");
5
- let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
2
+ const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
3
+ const require_directory_contract_api = require("./directory-contract-api.cjs");
4
+ const require_channel_setup = require("./channel.setup-mOFtsfYz.cjs");
6
5
  let openclaw_plugin_sdk_channel_core = require("openclaw/plugin-sdk/channel-core");
7
6
  let openclaw_plugin_sdk_channel_outbound = require("openclaw/plugin-sdk/channel-outbound");
8
7
  let openclaw_plugin_sdk_channel_pairing = require("openclaw/plugin-sdk/channel-pairing");
@@ -13,6 +12,7 @@ let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime
13
12
  let openclaw_plugin_sdk_status_helpers = require("openclaw/plugin-sdk/status-helpers");
14
13
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
15
14
  let typebox = require("typebox");
15
+ let openclaw_plugin_sdk_reply_reference = require("openclaw/plugin-sdk/reply-reference");
16
16
  let openclaw_plugin_sdk_approval_auth_runtime = require("openclaw/plugin-sdk/approval-auth-runtime");
17
17
  let openclaw_plugin_sdk_channel_actions = require("openclaw/plugin-sdk/channel-actions");
18
18
  let openclaw_plugin_sdk_routing = require("openclaw/plugin-sdk/routing");
@@ -23,46 +23,6 @@ let openclaw_plugin_sdk_runtime_group_policy = require("openclaw/plugin-sdk/runt
23
23
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
24
24
  let openclaw_plugin_sdk_channel_status = require("openclaw/plugin-sdk/channel-status");
25
25
  let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
26
- //#region extensions/msteams/src/approval-auth.ts
27
- const MSTEAMS_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
28
- function normalizeMSTeamsApproverId(value) {
29
- const normalized = require_resolve_allowlist.normalizeMSTeamsMessagingTarget(String(value));
30
- if (!normalized?.startsWith("user:")) return;
31
- const id = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(normalized.slice(5));
32
- if (!id) return;
33
- return MSTEAMS_ID_RE.test(id) ? id : void 0;
34
- }
35
- function resolveMSTeamsChannelConfig(cfg) {
36
- return cfg.channels?.msteams;
37
- }
38
- const msTeamsApprovalAuth = (0, openclaw_plugin_sdk_approval_auth_runtime.createChannelApprovalAuth)({
39
- channelLabel: "Microsoft Teams",
40
- resolveInputs: ({ cfg }) => {
41
- const channel = resolveMSTeamsChannelConfig(cfg);
42
- return {
43
- allowFrom: channel?.allowFrom,
44
- defaultTo: channel?.defaultTo
45
- };
46
- },
47
- normalizeApprover: normalizeMSTeamsApproverId,
48
- normalizeSenderId: (value) => {
49
- const trimmed = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(value);
50
- if (!trimmed) return;
51
- return MSTEAMS_ID_RE.test(trimmed) ? trimmed : void 0;
52
- }
53
- }).approvalAuth;
54
- //#endregion
55
- //#region extensions/msteams/src/doctor.ts
56
- const isMSTeamsMutableAllowEntry = (0, openclaw_plugin_sdk_channel_policy.buildMutableAllowEntryDetector)({
57
- prefixes: ["msteams:", "user:"],
58
- stableIdPattern: /^[^\s@]+$/
59
- });
60
- const collectMSTeamsMutableAllowlistWarnings = (0, openclaw_plugin_sdk_channel_policy.createDangerousNameMatchingMutableAllowlistWarningCollector)({
61
- channel: "msteams",
62
- detector: isMSTeamsMutableAllowEntry,
63
- collectLists: (scope) => (0, openclaw_plugin_sdk_channel_policy.collectStandardAllowlistLists)(scope)
64
- });
65
- //#endregion
66
26
  //#region extensions/msteams/src/policy.ts
67
27
  const teamScopeKey = (teamKey) => (0, openclaw_plugin_sdk_channel_policy.scopeKey)(["team", teamKey]);
68
28
  const channelScopeKey = (teamKey, channelKey) => (0, openclaw_plugin_sdk_channel_policy.scopeKey)(["team", teamKey], ["channel", channelKey]);
@@ -218,6 +178,115 @@ function resolveMSTeamsReplyPolicy(params) {
218
178
  };
219
179
  }
220
180
  //#endregion
181
+ //#region extensions/msteams/src/action-threading.ts
182
+ function stripConversationPrefix(raw) {
183
+ const trimmed = raw.trim();
184
+ if (/^conversation:/i.test(trimmed)) return trimmed.slice(13).trim();
185
+ return trimmed;
186
+ }
187
+ /** Normalize Teams conversation targets for equality (strips `conversation:` and `;messageid=`). */
188
+ function normalizeMSTeamsThreadingTarget(raw) {
189
+ const value = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(raw);
190
+ if (!value) return;
191
+ return require_resolve_allowlist.normalizeMSTeamsConversationId(stripConversationPrefix(value));
192
+ }
193
+ function extractMSTeamsResultConversationId(value) {
194
+ if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value)) return;
195
+ const direct = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(value.conversationId);
196
+ if (direct) return direct;
197
+ const receipt = (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(value.receipt) ? value.receipt : void 0;
198
+ if (!receipt) return;
199
+ const candidates = [...Array.isArray(receipt.raw) ? receipt.raw : [], ...Array.isArray(receipt.parts) ? receipt.parts.map((part) => (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(part) ? part.raw : void 0) : []];
200
+ for (const candidate of candidates) {
201
+ if (!(0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(candidate)) continue;
202
+ const conversationId = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(candidate.conversationId);
203
+ if (conversationId) return conversationId;
204
+ }
205
+ }
206
+ /** Recover the actual Teams conversation resolved by a successful tool send. */
207
+ function extractMSTeamsToolSendResult(result, _send) {
208
+ const details = (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(result) && (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(result.details) ? result.details : void 0;
209
+ const conversationId = extractMSTeamsResultConversationId(details && (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(details.result) ? details.result : void 0);
210
+ if (!conversationId) return null;
211
+ const normalizedConversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(stripConversationPrefix(conversationId));
212
+ return normalizedConversationId ? { to: `conversation:${normalizedConversationId}` } : null;
213
+ }
214
+ function msteamsContextTargetsMatch(target, context) {
215
+ const normalizedTarget = normalizeMSTeamsThreadingTarget(target);
216
+ if (!normalizedTarget) return false;
217
+ const currentChannel = normalizeMSTeamsThreadingTarget(context.currentChannelId);
218
+ if (currentChannel && currentChannel === normalizedTarget) return true;
219
+ const currentMessaging = normalizeMSTeamsThreadingTarget(context.currentMessagingTarget);
220
+ return Boolean(currentMessaging && currentMessaging === normalizedTarget);
221
+ }
222
+ function resolveMSTeamsAutoThreadId(params) {
223
+ const explicitThreadId = require_resolve_allowlist.extractMSTeamsConversationMessageId(params.to);
224
+ if (explicitThreadId) return explicitThreadId;
225
+ const context = params.toolContext;
226
+ if (!context?.currentChannelId && !context?.currentMessagingTarget) return;
227
+ if (!msteamsContextTargetsMatch(params.to, context)) return;
228
+ const graphTarget = context.currentGraphChannelId ?? context.currentMessagingTarget;
229
+ const { team, channel } = graphTarget ? require_resolve_allowlist.parseMSTeamsTeamChannelInput(graphTarget) : {
230
+ team: void 0,
231
+ channel: void 0
232
+ };
233
+ const routeConfig = resolveMSTeamsRouteConfig({
234
+ cfg: params.cfg,
235
+ teamId: team,
236
+ conversationId: channel,
237
+ allowNameMatching: false
238
+ });
239
+ const { replyStyle } = resolveMSTeamsReplyPolicy({
240
+ isDirectMessage: false,
241
+ globalConfig: params.cfg,
242
+ teamConfig: routeConfig.teamConfig,
243
+ channelConfig: routeConfig.channelConfig
244
+ });
245
+ if (replyStyle === "top-level") return;
246
+ if (!context.currentThreadTs) return;
247
+ if (context.replyToMode !== "all" && !(0, openclaw_plugin_sdk_reply_reference.isSingleUseReplyToMode)(context.replyToMode ?? "off")) return;
248
+ if ((0, openclaw_plugin_sdk_reply_reference.isSingleUseReplyToMode)(context.replyToMode ?? "off") && context.hasRepliedRef?.value) return;
249
+ return context.currentThreadTs;
250
+ }
251
+ //#endregion
252
+ //#region extensions/msteams/src/approval-auth.ts
253
+ const MSTEAMS_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
254
+ function normalizeMSTeamsApproverId(value) {
255
+ const normalized = require_resolve_allowlist.normalizeMSTeamsMessagingTarget(String(value));
256
+ const id = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(normalized?.startsWith("user:") ? normalized.slice(5) : normalized);
257
+ return id && MSTEAMS_ID_RE.test(id) ? id : void 0;
258
+ }
259
+ function resolveMSTeamsChannelConfig(cfg) {
260
+ return cfg.channels?.msteams;
261
+ }
262
+ const msTeamsApprovalAuth = (0, openclaw_plugin_sdk_approval_auth_runtime.createChannelApprovalAuth)({
263
+ channelLabel: "Microsoft Teams",
264
+ resolveInputs: ({ cfg }) => {
265
+ const channel = resolveMSTeamsChannelConfig(cfg);
266
+ return {
267
+ allowFrom: channel?.allowFrom,
268
+ defaultTo: channel?.defaultTo
269
+ };
270
+ },
271
+ normalizeApprover: normalizeMSTeamsApproverId,
272
+ normalizeSenderId: (value) => {
273
+ const trimmed = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(value);
274
+ if (!trimmed) return;
275
+ return MSTEAMS_ID_RE.test(trimmed) ? trimmed : void 0;
276
+ }
277
+ }).approvalAuth;
278
+ //#endregion
279
+ //#region extensions/msteams/src/doctor.ts
280
+ const isMSTeamsMutableAllowEntry = (0, openclaw_plugin_sdk_channel_policy.buildMutableAllowEntryDetector)({
281
+ prefixes: ["msteams:", "user:"],
282
+ stableIdPattern: /^[^\s@]+$/
283
+ });
284
+ const collectMSTeamsMutableAllowlistWarnings = (0, openclaw_plugin_sdk_channel_policy.createDangerousNameMatchingMutableAllowlistWarningCollector)({
285
+ channel: "msteams",
286
+ detector: isMSTeamsMutableAllowEntry,
287
+ collectLists: (scope) => (0, openclaw_plugin_sdk_channel_policy.collectStandardAllowlistLists)(scope)
288
+ });
289
+ //#endregion
221
290
  //#region extensions/msteams/src/presentation.ts
222
291
  const MSTEAMS_PRESENTATION_CAPABILITIES = {
223
292
  supported: true,
@@ -434,8 +503,8 @@ async function resolveAllowedChannelTarget(cfg, target) {
434
503
  allowNameMatching: (0, openclaw_plugin_sdk_dangerous_name_runtime.isDangerousNameMatchingEnabled)(teams)
435
504
  });
436
505
  const stableTarget = await resolveStableChannelTarget(cfg, target);
506
+ if (!directRoute.allowlistConfigured && groupPolicy !== "open" && stableTarget) throw new openclaw_plugin_sdk_channel_actions.ToolAuthorizationError("Microsoft Teams read target is not allowed. Configure channels.msteams.teams.<team>.channels for this channel, or deliberately set channels.msteams.groupPolicy to \"open\".");
437
507
  if (directRoute.allowed) return stableTarget;
438
- if (!directRoute.allowlistConfigured) return groupPolicy === "open" ? stableTarget : void 0;
439
508
  if (!stableTarget || !teams?.teams) return;
440
509
  const [stableTeamId, stableChannelId] = stableTarget.split("/", 2);
441
510
  if (!stableTeamId || !stableChannelId) return;
@@ -545,20 +614,32 @@ function resolveMSTeamsRouteSessionKey(params) {
545
614
  }
546
615
  //#endregion
547
616
  //#region extensions/msteams/src/session-route.ts
617
+ function inferMSTeamsTargetChatType(raw) {
618
+ const target = (0, openclaw_plugin_sdk_channel_core.stripChannelTargetPrefix)(raw, "msteams", "teams");
619
+ if (!target) return;
620
+ const lower = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(target);
621
+ const rawId = (0, openclaw_plugin_sdk_channel_core.stripTargetKindPrefix)(target);
622
+ if (!rawId) return;
623
+ const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawId);
624
+ if (lower.startsWith("user:") || /^[0-9a-f-]{16,}$/i.test(conversationId)) return "direct";
625
+ if (/@thread\.tacv2/i.test(conversationId)) return "channel";
626
+ return /^19:.+@thread\.(?:skype|v2)$/i.test(conversationId) ? "group" : void 0;
627
+ }
548
628
  function resolveMSTeamsOutboundSessionRoute(params) {
549
629
  const trimmed = (0, openclaw_plugin_sdk_channel_core.stripChannelTargetPrefix)(params.target, "msteams", "teams");
550
630
  if (!trimmed) return null;
551
- const isUser = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(trimmed).startsWith("user:");
631
+ const resolvedKind = params.resolvedTarget?.kind;
632
+ const targetChatType = inferMSTeamsTargetChatType(trimmed);
633
+ const isUser = resolvedKind === "user" || targetChatType === "direct";
552
634
  const rawId = (0, openclaw_plugin_sdk_channel_core.stripTargetKindPrefix)(trimmed);
553
635
  if (!rawId) return null;
554
636
  const conversationId = require_resolve_allowlist.normalizeMSTeamsConversationId(rawId);
555
- const isChannel = !isUser && /@thread\.tacv2/i.test(conversationId);
637
+ const isChannel = !isUser && targetChatType === "channel";
556
638
  const embeddedThreadId = require_resolve_allowlist.extractMSTeamsConversationMessageId(rawId);
557
639
  const explicitThreadId = params.threadId ?? params.replyToId;
558
640
  const channelThreadId = embeddedThreadId ?? (explicitThreadId !== void 0 && explicitThreadId !== null ? String(explicitThreadId) : void 0);
559
- const resolvedKind = params.resolvedTarget?.kind;
560
641
  const isCanonicalUserId = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(conversationId);
561
- const recipientSessionExact = (isUser || resolvedKind === "user") && isCanonicalUserId || (isChannel ? channelThreadId !== void 0 : resolvedKind === "group");
642
+ const recipientSessionExact = isUser && isCanonicalUserId || (isChannel ? channelThreadId !== void 0 : resolvedKind === "group");
562
643
  const route = (0, openclaw_plugin_sdk_channel_core.buildChannelOutboundSessionRoute)({
563
644
  cfg: params.cfg,
564
645
  agentId: params.agentId,
@@ -604,7 +685,13 @@ const collectMSTeamsSecurityWarnings = (0, openclaw_plugin_sdk_channel_policy.cr
604
685
  resolveGroupPolicy: ({ cfg }) => cfg.channels?.msteams?.groupPolicy,
605
686
  collect: ({ groupPolicy }) => groupPolicy === "open" ? ["- MS Teams groups: groupPolicy=\"open\" allows any member to trigger (mention-gated). Set channels.msteams.groupPolicy=\"allowlist\" + channels.msteams.groupAllowFrom to restrict senders."] : []
606
687
  });
607
- const loadMSTeamsChannelRuntime = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeNamedExport)(() => Promise.resolve().then(() => require("./channel.runtime-DjY6d_hd.cjs")), "msTeamsChannelRuntime");
688
+ const collectMSTeamsSecurityFindings = openclaw_plugin_sdk_channel_policy.createConditionalWarningCollector.findings({
689
+ collectWarnings: collectMSTeamsSecurityWarnings,
690
+ checkId: "channels.msteams.groups.open",
691
+ severity: "critical",
692
+ title: "MS Teams security warning"
693
+ });
694
+ const loadMSTeamsChannelRuntime = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeNamedExport)(() => Promise.resolve().then(() => require("./channel.runtime-Bkzj8jZ0.cjs")), "msTeamsChannelRuntime");
608
695
  function jsonActionResult(data) {
609
696
  return {
610
697
  content: [{
@@ -700,7 +787,7 @@ function resolveActionContent(params) {
700
787
  return typeof params.text === "string" ? params.text : typeof params.content === "string" ? params.content : typeof params.message === "string" ? params.message : "";
701
788
  }
702
789
  function readOptionalTrimmedString(params, key) {
703
- return typeof params[key] === "string" ? params[key].trim() || void 0 : void 0;
790
+ return (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(params[key]);
704
791
  }
705
792
  function resolveActionUploadFilePath(params) {
706
793
  for (const key of [
@@ -712,67 +799,35 @@ function resolveActionUploadFilePath(params) {
712
799
  if (value.trim()) return value;
713
800
  }
714
801
  }
715
- function resolveRequiredActionTarget(params) {
716
- const to = params.graphOnly ? resolveGraphActionTarget(params.toolParams, params.currentChannelId, params.currentGraphChannelId, params.currentChatType) : resolveActionTarget(params.toolParams, params.currentChannelId);
802
+ function resolveMSTeamsActionTarget(params) {
803
+ return params.graphOnly ? resolveGraphActionTarget(params.toolParams, params.currentChannelId, params.currentGraphChannelId, params.currentChatType) : resolveActionTarget(params.toolParams, params.currentChannelId);
804
+ }
805
+ async function runWithRequiredActionTarget(params) {
806
+ const to = resolveMSTeamsActionTarget(params);
717
807
  if (!to) return actionError(`${params.actionLabel} requires a target (to).`);
718
- return to;
808
+ return await params.run(to);
719
809
  }
720
- function resolveRequiredActionMessageTarget(params) {
721
- const to = params.graphOnly ? resolveGraphActionTarget(params.toolParams, params.currentChannelId, params.currentGraphChannelId, params.currentChatType) : resolveActionTarget(params.toolParams, params.currentChannelId);
810
+ async function runWithRequiredActionMessageTarget(params) {
811
+ const to = resolveMSTeamsActionTarget(params);
722
812
  const messageId = resolveActionMessageId(params.toolParams);
723
813
  if (!to || !messageId) return actionError(`${params.actionLabel} requires a target (to) and messageId.`);
724
- return {
814
+ return await params.run({
725
815
  to,
726
816
  messageId
727
- };
817
+ });
728
818
  }
729
- function resolveRequiredActionPinnedMessageTarget(params) {
730
- const to = params.graphOnly ? resolveGraphActionTarget(params.toolParams, params.currentChannelId, params.currentGraphChannelId, params.currentChatType) : resolveActionTarget(params.toolParams, params.currentChannelId);
819
+ async function runWithRequiredActionPinnedMessageTarget(params) {
820
+ const to = resolveMSTeamsActionTarget(params);
731
821
  const pinnedMessageId = resolveActionPinnedMessageId(params.toolParams);
732
822
  if (!to || !pinnedMessageId) return actionError(`${params.actionLabel} requires a target (to) and pinnedMessageId.`);
733
- return {
823
+ return await params.run({
734
824
  to,
735
825
  pinnedMessageId
736
- };
737
- }
738
- async function runWithRequiredActionTarget(params) {
739
- const to = resolveRequiredActionTarget({
740
- actionLabel: params.actionLabel,
741
- toolParams: params.toolParams,
742
- currentChannelId: params.currentChannelId,
743
- currentGraphChannelId: params.currentGraphChannelId,
744
- currentChatType: params.currentChatType,
745
- graphOnly: params.graphOnly
746
826
  });
747
- if (typeof to !== "string") return to;
748
- return await params.run(to);
749
- }
750
- async function runWithRequiredActionMessageTarget(params) {
751
- const target = resolveRequiredActionMessageTarget({
752
- actionLabel: params.actionLabel,
753
- toolParams: params.toolParams,
754
- currentChannelId: params.currentChannelId,
755
- currentGraphChannelId: params.currentGraphChannelId,
756
- currentChatType: params.currentChatType,
757
- graphOnly: params.graphOnly
758
- });
759
- if ("isError" in target) return target;
760
- return await params.run(target);
761
- }
762
- async function runWithRequiredActionPinnedMessageTarget(params) {
763
- const target = resolveRequiredActionPinnedMessageTarget({
764
- actionLabel: params.actionLabel,
765
- toolParams: params.toolParams,
766
- currentChannelId: params.currentChannelId,
767
- currentGraphChannelId: params.currentGraphChannelId,
768
- currentChatType: params.currentChatType,
769
- graphOnly: params.graphOnly
770
- });
771
- if ("isError" in target) return target;
772
- return await params.run(target);
773
827
  }
774
828
  function describeMSTeamsMessageTool({ cfg }) {
775
- const enabled = cfg.channels?.msteams?.enabled !== false && Boolean(require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams));
829
+ const account = require_channel_setup.resolveMSTeamsAccount(cfg);
830
+ const enabled = account.enabled && account.configured && account.tokenStatus === "available";
776
831
  return {
777
832
  actions: enabled ? [
778
833
  "upload-file",
@@ -842,38 +897,13 @@ const msteamsMessageAdapter = (0, openclaw_plugin_sdk_channel_outbound.createCha
842
897
  });
843
898
  const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlugin)({
844
899
  base: {
845
- id: "msteams",
846
- meta: {
847
- ...require_setup_surface.msteamsMeta,
848
- aliases: [...require_setup_surface.msteamsMeta.aliases]
849
- },
850
- setupWizard: require_setup_surface.msteamsSetupWizard,
851
- capabilities: {
852
- chatTypes: [
853
- "direct",
854
- "channel",
855
- "thread"
856
- ],
857
- polls: true,
858
- threads: true,
859
- media: true
860
- },
900
+ ...require_channel_setup.msteamsSetupPlugin,
861
901
  streaming: { blockStreamingCoalesceDefaults: {
862
902
  minChars: 1500,
863
903
  idleMs: 1e3
864
904
  } },
865
905
  agentPrompt: { messageToolHints: () => ["- Adaptive Cards supported. Use `action=send` with `card={type,version,body}` to send rich cards.", "- MSTeams targeting: omit `target` to reply to the current conversation (auto-inferred). Explicit targets: `user:ID` or `user:Display Name` (requires Graph API) for DMs, `conversation:19:...@thread.tacv2` for groups/channels. Prefer IDs over display names for speed."] },
866
906
  groups: { resolveToolPolicy: resolveMSTeamsGroupToolPolicy },
867
- reload: { configPrefixes: ["channels.msteams"] },
868
- configSchema: require_config_schema.MSTeamsChannelConfigSchema,
869
- config: {
870
- ...require_setup_surface.msteamsConfigAdapter,
871
- isConfigured: (_account, cfg) => Boolean(require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams)),
872
- describeAccount: (account) => (0, openclaw_plugin_sdk_account_helpers.describeAccountSnapshot)({
873
- account,
874
- configured: account.configured
875
- })
876
- },
877
907
  approvalCapability: msTeamsApprovalAuth,
878
908
  doctor: {
879
909
  dmAllowFromMode: "topOnly",
@@ -882,12 +912,11 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
882
912
  warnOnEmptyGroupSenderAllowlist: true,
883
913
  collectMutableAllowlistWarnings: collectMSTeamsMutableAllowlistWarnings
884
914
  },
885
- setup: require_setup_surface.msteamsSetupAdapter,
886
- setupContract: require_setup_surface.msteamsSetupContract,
887
915
  messaging: {
888
916
  targetPrefixes: ["msteams", "teams"],
889
917
  directTargetStyle: "user-prefixed",
890
918
  normalizeTarget: require_resolve_allowlist.normalizeMSTeamsMessagingTarget,
919
+ inferTargetChatType: ({ to }) => inferMSTeamsTargetChatType(to),
891
920
  resolveOutboundSessionRoute: (params) => resolveMSTeamsOutboundSessionRoute(params),
892
921
  targetResolver: {
893
922
  looksLikeId: (raw) => require_resolve_allowlist.looksLikeMSTeamsTargetId(raw),
@@ -896,34 +925,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
896
925
  },
897
926
  message: msteamsMessageAdapter,
898
927
  directory: (0, openclaw_plugin_sdk_directory_runtime.createChannelDirectoryAdapter)({
899
- self: async ({ cfg }) => {
900
- const creds = require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams);
901
- if (!creds) return null;
902
- return {
903
- kind: "user",
904
- id: creds.appId,
905
- name: creds.appId
906
- };
907
- },
908
- listPeers: async ({ cfg, query, limit }) => (0, openclaw_plugin_sdk_directory_runtime.listDirectoryEntriesFromSources)({
909
- kind: "user",
910
- sources: [cfg.channels?.msteams?.allowFrom ?? [], Object.keys(cfg.channels?.msteams?.dms ?? {})],
911
- query,
912
- limit,
913
- normalizeId: (raw) => {
914
- const normalized = require_resolve_allowlist.normalizeMSTeamsMessagingTarget(raw) ?? raw;
915
- const lowered = normalized.toLowerCase();
916
- if (lowered.startsWith("user:") || lowered.startsWith("conversation:")) return normalized;
917
- return `user:${normalized}`;
918
- }
919
- }),
920
- listGroups: async ({ cfg, query, limit }) => (0, openclaw_plugin_sdk_directory_runtime.listDirectoryEntriesFromSources)({
921
- kind: "group",
922
- sources: [Object.values(cfg.channels?.msteams?.teams ?? {}).flatMap((team) => Object.keys(team.channels ?? {}))],
923
- query,
924
- limit,
925
- normalizeId: (raw) => `conversation:${raw.replace(/^conversation:/i, "").trim()}`
926
- }),
928
+ ...require_directory_contract_api.msteamsDirectoryContractPlugin.directory,
927
929
  ...(0, openclaw_plugin_sdk_directory_runtime.createRuntimeDirectoryLiveAdapter)({
928
930
  getRuntime: loadMSTeamsChannelRuntime,
929
931
  listPeersLive: (runtime) => runtime.listMSTeamsDirectoryPeersLive,
@@ -1038,13 +1040,20 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1038
1040
  return results;
1039
1041
  } },
1040
1042
  actions: {
1043
+ providerOwnedReadGates: true,
1041
1044
  describeMessageTool: describeMSTeamsMessageTool,
1045
+ extractToolSendResult: ({ result, send }) => extractMSTeamsToolSendResult(result, send),
1042
1046
  requiresTrustedRequesterSender: ({ action, toolContext }) => (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(toolContext?.currentChannelProvider)?.toLowerCase() === "msteams" && MSTEAMS_GROUP_MANAGEMENT_ACTIONS.has(action),
1043
1047
  handleAction: async (ctx) => {
1044
1048
  if (MSTEAMS_GROUP_MANAGEMENT_ACTIONS.has(ctx.action)) {
1045
1049
  const authError = requireMSTeamsGroupManagementAuthorization(ctx);
1046
1050
  if (authError) return authError;
1047
1051
  }
1052
+ const authorizeActionTarget = (target) => assertMSTeamsReadTargetAllowed({
1053
+ cfg: ctx.cfg,
1054
+ ctx,
1055
+ target
1056
+ });
1048
1057
  const presentation = ctx.action === "send" ? (0, openclaw_plugin_sdk_interactive_runtime.normalizeMessagePresentation)(ctx.params.presentation) : void 0;
1049
1058
  if (ctx.action === "send" && presentation) {
1050
1059
  const card = buildMSTeamsPresentationCard({
@@ -1089,6 +1098,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1089
1098
  text: resolveActionContent(ctx.params),
1090
1099
  mediaUrl,
1091
1100
  filename: readOptionalTrimmedString(ctx.params, "filename") ?? readOptionalTrimmedString(ctx.params, "title"),
1101
+ mediaAccess: ctx.mediaAccess,
1092
1102
  mediaLocalRoots: ctx.mediaLocalRoots,
1093
1103
  mediaReadFile: ctx.mediaReadFile
1094
1104
  });
@@ -1116,11 +1126,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1116
1126
  toolParams: ctx.params,
1117
1127
  currentChannelId: ctx.toolContext?.currentChannelId,
1118
1128
  run: async (target) => {
1119
- const to = await assertMSTeamsReadTargetAllowed({
1120
- cfg: ctx.cfg,
1121
- ctx,
1122
- target: target.to
1123
- });
1129
+ const to = await authorizeActionTarget(target.to);
1124
1130
  const { editMessageMSTeams } = await loadMSTeamsChannelRuntime();
1125
1131
  return jsonMSTeamsConversationResult((await editMessageMSTeams({
1126
1132
  cfg: ctx.cfg,
@@ -1136,11 +1142,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1136
1142
  toolParams: ctx.params,
1137
1143
  currentChannelId: ctx.toolContext?.currentChannelId,
1138
1144
  run: async (target) => {
1139
- const to = await assertMSTeamsReadTargetAllowed({
1140
- cfg: ctx.cfg,
1141
- ctx,
1142
- target: target.to
1143
- });
1145
+ const to = await authorizeActionTarget(target.to);
1144
1146
  const { deleteMessageMSTeams } = await loadMSTeamsChannelRuntime();
1145
1147
  return jsonMSTeamsConversationResult((await deleteMessageMSTeams({
1146
1148
  cfg: ctx.cfg,
@@ -1149,19 +1151,18 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1149
1151
  })).conversationId);
1150
1152
  }
1151
1153
  });
1152
- if (ctx.action === "read") return await runWithRequiredActionMessageTarget({
1153
- actionLabel: "Read",
1154
+ const graphActionTarget = {
1154
1155
  toolParams: ctx.params,
1155
1156
  currentChannelId: ctx.toolContext?.currentChannelId,
1156
1157
  currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1157
1158
  currentChatType: ctx.toolContext?.currentChatType,
1158
- graphOnly: true,
1159
+ graphOnly: true
1160
+ };
1161
+ if (ctx.action === "read") return await runWithRequiredActionMessageTarget({
1162
+ actionLabel: "Read",
1163
+ ...graphActionTarget,
1159
1164
  run: async (target) => {
1160
- const to = await assertMSTeamsReadTargetAllowed({
1161
- cfg: ctx.cfg,
1162
- ctx,
1163
- target: target.to
1164
- });
1165
+ const to = await authorizeActionTarget(target.to);
1165
1166
  const { getMessageMSTeams } = await loadMSTeamsChannelRuntime();
1166
1167
  return jsonMSTeamsOkActionResult("read", { message: await getMessageMSTeams({
1167
1168
  cfg: ctx.cfg,
@@ -1172,17 +1173,9 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1172
1173
  });
1173
1174
  if (ctx.action === "pin") return await runWithRequiredActionMessageTarget({
1174
1175
  actionLabel: "Pin",
1175
- toolParams: ctx.params,
1176
- currentChannelId: ctx.toolContext?.currentChannelId,
1177
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1178
- currentChatType: ctx.toolContext?.currentChatType,
1179
- graphOnly: true,
1176
+ ...graphActionTarget,
1180
1177
  run: async (target) => {
1181
- const to = await assertMSTeamsReadTargetAllowed({
1182
- cfg: ctx.cfg,
1183
- ctx,
1184
- target: target.to
1185
- });
1178
+ const to = await authorizeActionTarget(target.to);
1186
1179
  const { pinMessageMSTeams } = await loadMSTeamsChannelRuntime();
1187
1180
  return jsonMSTeamsActionResult("pin", await pinMessageMSTeams({
1188
1181
  cfg: ctx.cfg,
@@ -1193,17 +1186,9 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1193
1186
  });
1194
1187
  if (ctx.action === "unpin") return await runWithRequiredActionPinnedMessageTarget({
1195
1188
  actionLabel: "Unpin",
1196
- toolParams: ctx.params,
1197
- currentChannelId: ctx.toolContext?.currentChannelId,
1198
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1199
- currentChatType: ctx.toolContext?.currentChatType,
1200
- graphOnly: true,
1189
+ ...graphActionTarget,
1201
1190
  run: async (target) => {
1202
- const to = await assertMSTeamsReadTargetAllowed({
1203
- cfg: ctx.cfg,
1204
- ctx,
1205
- target: target.to
1206
- });
1191
+ const to = await authorizeActionTarget(target.to);
1207
1192
  const { unpinMessageMSTeams } = await loadMSTeamsChannelRuntime();
1208
1193
  return jsonMSTeamsActionResult("unpin", await unpinMessageMSTeams({
1209
1194
  cfg: ctx.cfg,
@@ -1214,17 +1199,9 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1214
1199
  });
1215
1200
  if (ctx.action === "list-pins") return await runWithRequiredActionTarget({
1216
1201
  actionLabel: "List-pins",
1217
- toolParams: ctx.params,
1218
- currentChannelId: ctx.toolContext?.currentChannelId,
1219
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1220
- currentChatType: ctx.toolContext?.currentChatType,
1221
- graphOnly: true,
1202
+ ...graphActionTarget,
1222
1203
  run: async (to) => {
1223
- const allowedTarget = await assertMSTeamsReadTargetAllowed({
1224
- cfg: ctx.cfg,
1225
- ctx,
1226
- target: to
1227
- });
1204
+ const allowedTarget = await authorizeActionTarget(to);
1228
1205
  const { listPinsMSTeams } = await loadMSTeamsChannelRuntime();
1229
1206
  return jsonMSTeamsOkActionResult("list-pins", await listPinsMSTeams({
1230
1207
  cfg: ctx.cfg,
@@ -1234,11 +1211,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1234
1211
  });
1235
1212
  if (ctx.action === "react") return await runWithRequiredActionMessageTarget({
1236
1213
  actionLabel: "React",
1237
- toolParams: ctx.params,
1238
- currentChannelId: ctx.toolContext?.currentChannelId,
1239
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1240
- currentChatType: ctx.toolContext?.currentChatType,
1241
- graphOnly: true,
1214
+ ...graphActionTarget,
1242
1215
  run: async (target) => {
1243
1216
  const emoji = typeof ctx.params.emoji === "string" ? ctx.params.emoji.trim() : "";
1244
1217
  const remove = typeof ctx.params.remove === "boolean" ? ctx.params.remove : false;
@@ -1253,11 +1226,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1253
1226
  validTypes: [...MSTEAMS_REACTION_TYPES]
1254
1227
  }
1255
1228
  };
1256
- const to = await assertMSTeamsReadTargetAllowed({
1257
- cfg: ctx.cfg,
1258
- ctx,
1259
- target: target.to
1260
- });
1229
+ const to = await authorizeActionTarget(target.to);
1261
1230
  if (remove) {
1262
1231
  const { unreactMessageMSTeams } = await loadMSTeamsChannelRuntime();
1263
1232
  return jsonMSTeamsActionResult("react", {
@@ -1285,17 +1254,9 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1285
1254
  });
1286
1255
  if (ctx.action === "reactions") return await runWithRequiredActionMessageTarget({
1287
1256
  actionLabel: "Reactions",
1288
- toolParams: ctx.params,
1289
- currentChannelId: ctx.toolContext?.currentChannelId,
1290
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1291
- currentChatType: ctx.toolContext?.currentChatType,
1292
- graphOnly: true,
1257
+ ...graphActionTarget,
1293
1258
  run: async (target) => {
1294
- const to = await assertMSTeamsReadTargetAllowed({
1295
- cfg: ctx.cfg,
1296
- ctx,
1297
- target: target.to
1298
- });
1259
+ const to = await authorizeActionTarget(target.to);
1299
1260
  const { listReactionsMSTeams } = await loadMSTeamsChannelRuntime();
1300
1261
  return jsonMSTeamsOkActionResult("reactions", await listReactionsMSTeams({
1301
1262
  cfg: ctx.cfg,
@@ -1306,17 +1267,9 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1306
1267
  });
1307
1268
  if (ctx.action === "search") return await runWithRequiredActionTarget({
1308
1269
  actionLabel: "Search",
1309
- toolParams: ctx.params,
1310
- currentChannelId: ctx.toolContext?.currentChannelId,
1311
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1312
- currentChatType: ctx.toolContext?.currentChatType,
1313
- graphOnly: true,
1270
+ ...graphActionTarget,
1314
1271
  run: async (to) => {
1315
- const allowedTarget = await assertMSTeamsReadTargetAllowed({
1316
- cfg: ctx.cfg,
1317
- ctx,
1318
- target: to
1319
- });
1272
+ const allowedTarget = await authorizeActionTarget(to);
1320
1273
  const query = resolveActionQuery(ctx.params);
1321
1274
  if (!query) return actionError("Search requires a target (to) and query.");
1322
1275
  const limit = typeof ctx.params.limit === "number" ? ctx.params.limit : void 0;
@@ -1336,17 +1289,9 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1336
1289
  if (!userId) return actionError("member-info requires a userId.");
1337
1290
  return await runWithRequiredActionTarget({
1338
1291
  actionLabel: "member-info",
1339
- toolParams: ctx.params,
1340
- currentChannelId: ctx.toolContext?.currentChannelId,
1341
- currentGraphChannelId: resolveCurrentGraphActionTarget(ctx.toolContext),
1342
- currentChatType: ctx.toolContext?.currentChatType,
1343
- graphOnly: true,
1292
+ ...graphActionTarget,
1344
1293
  run: async (target) => {
1345
- const to = await assertMSTeamsReadTargetAllowed({
1346
- cfg: ctx.cfg,
1347
- ctx,
1348
- target
1349
- });
1294
+ const to = await authorizeActionTarget(target);
1350
1295
  const currentRequesterId = isCurrentMSTeamsReadTarget({
1351
1296
  ctx,
1352
1297
  target: to
@@ -1379,11 +1324,7 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1379
1324
  const teamId = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(ctx.params.teamId) ?? "";
1380
1325
  const channelId = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(ctx.params.channelId) ?? "";
1381
1326
  if (!teamId || !channelId) return actionError("channel-info requires teamId and channelId.");
1382
- const [graphTeamId, graphChannelId] = (await assertMSTeamsReadTargetAllowed({
1383
- cfg: ctx.cfg,
1384
- ctx,
1385
- target: `${teamId}/${channelId}`
1386
- })).split("/", 2);
1327
+ const [graphTeamId, graphChannelId] = (await authorizeActionTarget(`${teamId}/${channelId}`)).split("/", 2);
1387
1328
  if (!graphTeamId || !graphChannelId) throw new Error("Authorized Microsoft Teams channel target is invalid.");
1388
1329
  const { getChannelInfoMSTeams } = await loadMSTeamsChannelRuntime();
1389
1330
  return jsonMSTeamsOkActionResult("channel-info", { channelInfo: (await getChannelInfoMSTeams({
@@ -1480,25 +1421,30 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1480
1421
  accountId: account.accountId,
1481
1422
  enabled: account.enabled,
1482
1423
  configured: account.configured,
1483
- extra: { port: runtime?.port ?? null }
1424
+ extra: {
1425
+ port: runtime?.port ?? null,
1426
+ tokenStatus: account.tokenStatus
1427
+ }
1484
1428
  })
1485
1429
  }),
1486
1430
  gateway: { startAccount: async (ctx) => {
1487
- const { monitorMSTeamsProvider } = await Promise.resolve().then(() => require("./src-B_BdEvcr.cjs"));
1431
+ const { monitorMSTeamsProvider } = await Promise.resolve().then(() => require("./src-C127-DcQ.cjs"));
1488
1432
  const port = ctx.cfg.channels?.msteams?.webhook?.port ?? 3978;
1489
- ctx.setStatus({
1433
+ const statusSink = (0, openclaw_plugin_sdk_channel_outbound.createAccountStatusSink)({
1490
1434
  accountId: ctx.accountId,
1491
- port
1435
+ setStatus: ctx.setStatus
1492
1436
  });
1437
+ statusSink({ port });
1493
1438
  ctx.log?.info(`starting provider (port ${port})`);
1494
1439
  return monitorMSTeamsProvider({
1495
1440
  cfg: ctx.cfg,
1496
1441
  runtime: ctx.runtime,
1497
- abortSignal: ctx.abortSignal
1442
+ abortSignal: ctx.abortSignal,
1443
+ statusSink
1498
1444
  });
1499
1445
  } }
1500
1446
  },
1501
- security: { collectWarnings: (0, openclaw_plugin_sdk_channel_policy.projectConfigWarningCollector)(collectMSTeamsSecurityWarnings) },
1447
+ security: { collectWarnings: ({ cfg }) => collectMSTeamsSecurityFindings({ cfg }) },
1502
1448
  pairing: { text: {
1503
1449
  idLabel: "msteamsUserId",
1504
1450
  message: openclaw_plugin_sdk_channel_status.PAIRING_APPROVED_MESSAGE,
@@ -1512,18 +1458,29 @@ const msteamsPlugin = (0, openclaw_plugin_sdk_channel_core.createChatChannelPlug
1512
1458
  });
1513
1459
  }
1514
1460
  } },
1515
- threading: { buildToolContext: ({ context, hasRepliedRef }) => {
1516
- const nativeChannelId = context.NativeChannelId?.trim();
1517
- const hasChannelRoute = Boolean(nativeChannelId && nativeChannelId.includes("/"));
1518
- return {
1519
- currentChannelId: (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(context.To),
1520
- currentChatType: context.ChatType === "direct" || context.ChatType === "group" || context.ChatType === "channel" ? context.ChatType : void 0,
1521
- currentMessagingTarget: hasChannelRoute ? nativeChannelId : void 0,
1522
- currentGraphChannelId: hasChannelRoute ? nativeChannelId : void 0,
1523
- currentThreadTs: context.ReplyToId,
1524
- hasRepliedRef
1525
- };
1526
- } },
1461
+ threading: {
1462
+ matchesToolContextTarget: ({ target, toolContext }) => msteamsContextTargetsMatch(target, toolContext),
1463
+ buildToolContext: ({ context, hasRepliedRef }) => {
1464
+ const nativeChannelId = context.NativeChannelId?.trim();
1465
+ const hasChannelRoute = Boolean(nativeChannelId && nativeChannelId.includes("/"));
1466
+ const isChannel = context.ChatType === "channel";
1467
+ const currentThreadTs = (context.MessageThreadId != null ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(String(context.MessageThreadId)) : void 0) ?? (isChannel ? (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(context.ReplyToId) : void 0);
1468
+ return {
1469
+ currentChannelId: (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalString)(context.To),
1470
+ currentChatType: context.ChatType === "direct" || context.ChatType === "group" || context.ChatType === "channel" ? context.ChatType : void 0,
1471
+ currentMessagingTarget: hasChannelRoute ? nativeChannelId : void 0,
1472
+ currentGraphChannelId: hasChannelRoute ? nativeChannelId : void 0,
1473
+ currentThreadTs,
1474
+ ...currentThreadTs ? { replyToMode: "all" } : {},
1475
+ hasRepliedRef
1476
+ };
1477
+ },
1478
+ resolveAutoThreadId: ({ cfg, to, toolContext }) => resolveMSTeamsAutoThreadId({
1479
+ cfg: cfg.channels?.msteams,
1480
+ to,
1481
+ toolContext
1482
+ })
1483
+ },
1527
1484
  outbound: msteamsChannelOutbound
1528
1485
  });
1529
1486
  //#endregion