@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.
- package/assets/icon.png +0 -0
- package/dist/.setup/{adapter.runtime-ChuVK6k_.cjs → adapter.runtime-BiWeMKXE.cjs} +24 -30
- package/dist/.setup/{approval-card-CPNH_q3P.cjs → approval-card-DWPDItvq.cjs} +6 -3
- package/dist/.setup/{approval-handler.runtime-DDxGPJDz.cjs → approval-handler.runtime-D1s7UR3U.cjs} +4 -4
- package/dist/.setup/bot-framework-service-url-BUhTe8F3.cjs +55 -0
- package/dist/.setup/{channel-Dzpbbht8.cjs → channel-ByzS7QJ0.cjs} +338 -220
- package/dist/.setup/{channel.runtime-TE49QvFv.cjs → channel.runtime-Baz8XDFs.cjs} +47 -144
- package/dist/.setup/{channel.setup-BVDfgdCc.cjs → channel.setup-DL8lcWT_.cjs} +6 -6
- package/dist/.setup/{config-schema-D22Lr1Qk.cjs → config-schema-0KoBzb0t.cjs} +24 -38
- package/dist/.setup/{messenger-BR1l4zw-.cjs → conversation-store-state-B7JuyZTm.cjs} +697 -297
- package/dist/.setup/{src-CpKfpP1m.cjs → monitor-BJ7IyH4y.cjs} +440 -663
- package/dist/.setup/{oauth-C6m7dvHj.cjs → oauth-DQjOnJ4l.cjs} +1 -1
- package/dist/.setup/{reaction-types-C7RA7Wxt.cjs → reaction-types-CQ4oSUe7.cjs} +2 -6
- package/dist/.setup/{resolve-allowlist-CHzaaWiC.cjs → resolve-allowlist-Pl_NQFYH.cjs} +55 -312
- package/dist/.setup/{rolldown-runtime-VH7oDXx4.cjs → rolldown-runtime-BloeesfJ.cjs} +22 -0
- package/dist/.setup/{send-D8ATH4QI.cjs → send-VUM7Sryb.cjs} +47 -97
- package/dist/.setup/{setup-plugin-api-DpiaA8z1.cjs → setup-plugin-api-Dyf8kF-l.cjs} +1 -1
- package/dist/.setup/{thread-session-CXgHK-yi.cjs → thread-session--rw3BTal.cjs} +2 -5
- package/dist/api.cjs +2 -2
- package/dist/channel-config-api.cjs +1 -1
- package/dist/channel-plugin-api.cjs +1 -1
- package/dist/configured-state.cjs +0 -1
- package/dist/directory-contract-api.cjs +1 -1
- package/dist/doctor-contract-api.cjs +201 -371
- package/dist/qa-runner-api.cjs +1 -1
- package/dist/runtime-api.cjs +0 -6
- package/dist/setup-entry.cjs +1 -1
- package/dist/setup-plugin-api.cjs +1 -1
- package/openclaw.plugin.json +46 -5
- package/package.json +10 -10
- package/dist/.setup/polls-BJ4-4uZm.cjs +0 -668
- package/dist/.setup/secret-input-C65t6kjM.cjs +0 -1
- 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-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
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
|
-
})).
|
|
26
|
+
})).flatMap((user) => {
|
|
26
27
|
const id = user.id?.trim();
|
|
27
|
-
if (!id) return
|
|
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
|
-
})
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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}
|
|
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
|
|
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
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
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 =
|
|
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 =
|
|
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:
|
|
706
|
-
|
|
707
|
-
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
2
|
-
require("./
|
|
3
|
-
const require_config_schema = require("./config-schema-
|
|
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-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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(),
|