@openclaw/msteams 2026.9.8 → 2026.10.1-beta.1

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 (25) hide show
  1. package/dist/.setup/{adapter.runtime-BiWeMKXE.cjs → adapter.runtime-D0HYByze.cjs} +9 -7
  2. package/dist/.setup/{approval-handler.runtime-D1s7UR3U.cjs → approval-handler.runtime-C-RJ3wXc.cjs} +3 -3
  3. package/dist/.setup/{channel-ByzS7QJ0.cjs → channel-BFhXodl2.cjs} +61 -75
  4. package/dist/.setup/{channel.runtime-Baz8XDFs.cjs → channel.runtime-D9jrw2SN.cjs} +22 -46
  5. package/dist/.setup/{channel.setup-DL8lcWT_.cjs → channel.setup-ss0TO-ap.cjs} +30 -36
  6. package/dist/.setup/{conversation-store-state-B7JuyZTm.cjs → conversation-store-state-f7V8CVNy.cjs} +62 -128
  7. package/dist/.setup/{monitor-BJ7IyH4y.cjs → monitor-DfSPCRkk.cjs} +71 -171
  8. package/dist/.setup/{oauth-DQjOnJ4l.cjs → oauth-CYxMYIOQ.cjs} +1 -1
  9. package/dist/.setup/{reaction-types-CQ4oSUe7.cjs → reaction-types-B-GEv57k.cjs} +1 -1
  10. package/dist/.setup/{resolve-allowlist-Pl_NQFYH.cjs → resolve-allowlist-Ct9yxQUw.cjs} +16 -134
  11. package/dist/.setup/{send-VUM7Sryb.cjs → send-7VV1iCai.cjs} +24 -70
  12. package/dist/.setup/{setup-plugin-api-Dyf8kF-l.cjs → setup-plugin-api-B0OFG32J.cjs} +1 -1
  13. package/dist/.setup/{thread-session--rw3BTal.cjs → thread-session-ClI-lSyG.cjs} +1 -1
  14. package/dist/.setup/token-config-DOt3XwVa.cjs +139 -0
  15. package/dist/api.cjs +2 -2
  16. package/dist/channel-plugin-api.cjs +1 -1
  17. package/dist/directory-contract-api.cjs +3 -2
  18. package/dist/doctor-backup-resources.cjs +21 -0
  19. package/dist/doctor-contract-api.cjs +37 -19
  20. package/dist/qa-runner-api.cjs +1 -1
  21. package/dist/runtime-api.cjs +0 -20
  22. package/dist/setup-entry.cjs +1 -1
  23. package/dist/setup-plugin-api.cjs +1 -1
  24. package/package.json +4 -4
  25. package/dist/.setup/delegated-state-u-ywZyZT.cjs +0 -70
@@ -1,5 +1,5 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-Pl_NQFYH.cjs");
2
- const require_delegated_state = require("./delegated-state-u-ywZyZT.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-Ct9yxQUw.cjs");
2
+ const require_token_config = require("./token-config-DOt3XwVa.cjs");
3
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");
@@ -26,7 +26,7 @@ const msteamsMeta = {
26
26
  };
27
27
  function resolveMSTeamsAccount(cfg) {
28
28
  const config = cfg.channels?.msteams;
29
- const credentials = require_resolve_allowlist.resolveMSTeamsCredentials(config);
29
+ const credentials = require_token_config.resolveMSTeamsCredentials(config);
30
30
  const certificatePath = credentials?.type === "federated" && !credentials.useManagedIdentity ? credentials.certificatePath : void 0;
31
31
  const certificate = certificatePath ? (0, openclaw_plugin_sdk_secret_file_runtime.tryReadSecretFileSync)(certificatePath, "Microsoft Teams certificate", void 0, { configPath: config?.certificatePath?.trim() ? "channels.msteams.certificatePath" : "env.MSTEAMS_CERTIFICATE_PATH" }) : void 0;
32
32
  const unavailable = certificate?.status === "configured_unavailable";
@@ -95,39 +95,36 @@ function createMSTeamsSetupWizardBase() {
95
95
  configuredScore: 2,
96
96
  unconfiguredScore: 0,
97
97
  includeStatusLine: true,
98
- resolveConfigured: ({ cfg }) => Boolean(require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams)) || require_resolve_allowlist.hasConfiguredMSTeamsCredentials(cfg.channels?.msteams)
98
+ resolveConfigured: ({ cfg }) => Boolean(require_token_config.resolveMSTeamsCredentials(cfg.channels?.msteams)) || require_token_config.hasConfiguredMSTeamsCredentials(cfg.channels?.msteams)
99
99
  }),
100
100
  credentials: [],
101
101
  finalize: async ({ cfg, prompter }) => {
102
- const resolved = require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams);
103
- const hasConfigCreds = require_resolve_allowlist.hasConfiguredMSTeamsCredentials(cfg.channels?.msteams);
102
+ const resolved = require_token_config.resolveMSTeamsCredentials(cfg.channels?.msteams);
103
+ const hasConfigCreds = require_token_config.hasConfiguredMSTeamsCredentials(cfg.channels?.msteams);
104
104
  const canUseEnv = Boolean(!hasConfigCreds && (0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(process.env.MSTEAMS_APP_ID) && (0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(process.env.MSTEAMS_APP_PASSWORD) && (0, openclaw_plugin_sdk_secret_input.normalizeSecretInputString)(process.env.MSTEAMS_TENANT_ID));
105
105
  let next = cfg;
106
- let appId = null;
107
- let appPassword = null;
108
- let tenantId = null;
109
106
  if (!resolved && !hasConfigCreds) await noteMSTeamsCredentialHelp(prompter);
110
- if (canUseEnv || hasConfigCreds) {
111
- if (await prompter.confirm({
112
- message: t$1(canUseEnv ? "wizard.msteams.envPrompt" : "wizard.msteams.credentialsKeep"),
113
- initialValue: true
114
- })) next = msteamsSetupAdapter.applyAccountConfig({
115
- cfg: next,
116
- accountId: openclaw_plugin_sdk_setup.DEFAULT_ACCOUNT_ID,
117
- input: {}
118
- });
119
- else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
120
- } else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
121
- if (appId && appPassword && tenantId) next = (0, openclaw_plugin_sdk_setup.patchTopLevelChannelConfigSection)({
107
+ if ((canUseEnv || hasConfigCreds) && await prompter.confirm({
108
+ message: t$1(canUseEnv ? "wizard.msteams.envPrompt" : "wizard.msteams.credentialsKeep"),
109
+ initialValue: true
110
+ })) next = msteamsSetupAdapter.applyAccountConfig({
122
111
  cfg: next,
123
- channel: channel$1,
124
- enabled: true,
125
- patch: {
126
- appId,
127
- appPassword,
128
- tenantId
129
- }
112
+ accountId: openclaw_plugin_sdk_setup.DEFAULT_ACCOUNT_ID,
113
+ input: {}
130
114
  });
115
+ else {
116
+ const { appId, appPassword, tenantId } = await promptMSTeamsCredentials(prompter);
117
+ if (appId && appPassword && tenantId) next = (0, openclaw_plugin_sdk_setup.patchTopLevelChannelConfigSection)({
118
+ cfg: next,
119
+ channel: channel$1,
120
+ enabled: true,
121
+ patch: {
122
+ appId,
123
+ appPassword,
124
+ tenantId
125
+ }
126
+ });
127
+ }
131
128
  return {
132
129
  cfg: next,
133
130
  accountId: openclaw_plugin_sdk_setup.DEFAULT_ACCOUNT_ID
@@ -140,12 +137,9 @@ function createMSTeamsSetupWizardBase() {
140
137
  const MAX_SAFE_RETRY_AFTER_SECONDS = Number.MAX_SAFE_INTEGER / 1e3;
141
138
  function formatUnknownError(err) {
142
139
  if (err instanceof Error) return err.message;
143
- if (typeof err === "string") return err;
144
- if (err === null) return "null";
145
- if (err === void 0) return "undefined";
146
- if (typeof err === "number" || typeof err === "boolean" || typeof err === "bigint") return String(err);
147
140
  if (typeof err === "symbol") return err.description ?? err.toString();
148
141
  if (typeof err === "function") return err.name ? `[function ${err.name}]` : "[function]";
142
+ if (err === null || typeof err !== "object") return String(err);
149
143
  try {
150
144
  return JSON.stringify(err) ?? "unknown error";
151
145
  } catch {
@@ -402,7 +396,7 @@ function listMSTeamsGroupEntries(cfg) {
402
396
  }
403
397
  async function resolveMSTeamsGroupAllowlist(params) {
404
398
  let resolvedEntries = params.entries.map((entry) => require_resolve_allowlist.parseMSTeamsTeamEntry(entry)).filter(Boolean);
405
- if (params.entries.length === 0 || !require_resolve_allowlist.resolveMSTeamsCredentials(params.cfg.channels?.msteams)) return resolvedEntries;
399
+ if (params.entries.length === 0 || !require_token_config.resolveMSTeamsCredentials(params.cfg.channels?.msteams)) return resolvedEntries;
406
400
  try {
407
401
  const lookups = await require_resolve_allowlist.resolveMSTeamsChannelAllowlist({
408
402
  cfg: params.cfg,
@@ -459,7 +453,7 @@ const msteamsSetupWizard = {
459
453
  const baseFinalize = msteamsSetupWizardBase.finalize;
460
454
  const baseResult = baseFinalize ? await baseFinalize(params) : void 0;
461
455
  let next = baseResult?.cfg ?? params.cfg;
462
- const finalCreds = require_resolve_allowlist.resolveMSTeamsCredentials(next.channels?.msteams);
456
+ const finalCreds = require_token_config.resolveMSTeamsCredentials(next.channels?.msteams);
463
457
  if (finalCreds?.type === "secret") {
464
458
  if (await params.prompter.confirm({
465
459
  message: t("wizard.msteams.delegatedAuthPrompt"),
@@ -475,7 +469,7 @@ const msteamsSetupWizard = {
475
469
  };
476
470
  let oauthModule;
477
471
  try {
478
- oauthModule = await Promise.resolve().then(() => require("./oauth-DQjOnJ4l.cjs"));
472
+ oauthModule = await Promise.resolve().then(() => require("./oauth-CYxMYIOQ.cjs"));
479
473
  } catch (err) {
480
474
  await noteDelegatedAuthFailure(err);
481
475
  return {
@@ -515,7 +509,7 @@ const msteamsSetupWizard = {
515
509
  progress.stop();
516
510
  throw err;
517
511
  }
518
- await require_delegated_state.saveMSTeamsDelegatedTokens(tokens);
512
+ await require_token_config.saveMSTeamsDelegatedTokens(tokens);
519
513
  progress.stop(t("wizard.msteams.delegatedAuthConfigured"));
520
514
  }
521
515
  }
@@ -1,14 +1,13 @@
1
1
  const require_rolldown_runtime = require("./rolldown-runtime-BloeesfJ.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("../runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-Pl_NQFYH.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-Ct9yxQUw.cjs");
5
5
  const require_bot_framework_service_url = require("./bot-framework-service-url-BUhTe8F3.cjs");
6
- const require_channel_setup = require("./channel.setup-DL8lcWT_.cjs");
6
+ const require_channel_setup = require("./channel.setup-ss0TO-ap.cjs");
7
7
  let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
8
8
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
9
9
  let openclaw_plugin_sdk_fetch_runtime = require("openclaw/plugin-sdk/fetch-runtime");
10
10
  let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
11
- let openclaw_plugin_sdk_file_lock = require("openclaw/plugin-sdk/file-lock");
12
11
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
13
12
  let openclaw_plugin_sdk_ssrf_runtime = require("openclaw/plugin-sdk/ssrf-runtime");
14
13
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
@@ -25,6 +24,7 @@ let openclaw_plugin_sdk_markdown_table_runtime = require("openclaw/plugin-sdk/ma
25
24
  let openclaw_plugin_sdk_blob_runtime = require("openclaw/plugin-sdk/blob-runtime");
26
25
  let node_crypto = require("node:crypto");
27
26
  node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
27
+ let openclaw_plugin_sdk_file_lock = require("openclaw/plugin-sdk/file-lock");
28
28
  let openclaw_plugin_sdk_keyed_async_queue = require("openclaw/plugin-sdk/keyed-async-queue");
29
29
  let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
30
30
  let openclaw_plugin_sdk_expect_runtime = require("openclaw/plugin-sdk/expect-runtime");
@@ -53,15 +53,6 @@ const CONSENT_UPLOAD_HOST_ALLOWLIST = [
53
53
  "graph.microsoft.de",
54
54
  "graph.microsoft.cn"
55
55
  ];
56
- /**
57
- * Validate that a consent upload URL is safe to PUT to.
58
- * Checks:
59
- * 1. Protocol is HTTPS
60
- * 2. Hostname matches the consent upload allowlist
61
- * 3. Resolved IP is not in a private/reserved range (anti-SSRF)
62
- *
63
- * @throws Error if the URL fails validation
64
- */
65
56
  async function validateConsentUploadUrl(url, opts) {
66
57
  let parsed;
67
58
  try {
@@ -119,10 +110,6 @@ function buildFileInfoCard(params) {
119
110
  }
120
111
  };
121
112
  }
122
- /**
123
- * Parse a fileConsent/invoke activity.
124
- * Returns null if the activity is not a file consent invoke.
125
- */
126
113
  function parseFileConsentInvoke(activity) {
127
114
  if (activity.name !== "fileConsent/invoke") return null;
128
115
  const value = activity.value;
@@ -136,8 +123,6 @@ function parseFileConsentInvoke(activity) {
136
123
  /**
137
124
  * Upload a file to the consent URL provided by Teams.
138
125
  * The URL is provided in the fileConsent/invoke response after user accepts.
139
- *
140
- * @throws Error if the URL fails SSRF validation (non-HTTPS, disallowed host, private IP)
141
126
  */
142
127
  async function uploadToConsentUrl(params) {
143
128
  await validateConsentUploadUrl(params.url, params.validationOpts);
@@ -435,6 +420,7 @@ function setPendingUploadActivityId(uploadId, activityId) {
435
420
  }
436
421
  //#endregion
437
422
  //#region extensions/msteams/src/file-consent-helpers.ts
423
+ const FILE_CONSENT_THRESHOLD_BYTES = 4194304;
438
424
  function buildConsentActivity(params) {
439
425
  const { media, description, uploadId } = params;
440
426
  return {
@@ -447,15 +433,7 @@ function buildConsentActivity(params) {
447
433
  })]
448
434
  };
449
435
  }
450
- /**
451
- * Prepare a FileConsentCard activity for large files or non-images in personal chats.
452
- * Returns the activity object and uploadId - caller is responsible for sending.
453
- *
454
- * This variant only writes to the in-memory store. Use it when the caller and
455
- * the `fileConsent/invoke` handler share the same process (for example the
456
- * messenger reply path). For proactive CLI sends where the invoke arrives in
457
- * a different process, use {@link prepareFileConsentActivityFs} instead.
458
- */
436
+ /** In-process replies keep consent bytes in memory; CLI sends use the persisted variant below. */
459
437
  function prepareFileConsentActivity(params) {
460
438
  const { media, conversationId, description } = params;
461
439
  const uploadId = storePendingUpload({
@@ -473,42 +451,20 @@ function prepareFileConsentActivity(params) {
473
451
  uploadId
474
452
  };
475
453
  }
476
- /**
477
- * Prepare a FileConsentCard activity and persist the pending upload to the
478
- * filesystem so a different process can read it when the user accepts.
479
- *
480
- * This is used by the proactive CLI `message send --media` path: the CLI
481
- * process sends the card and exits, but the `fileConsent/invoke` callback is
482
- * delivered to the long-lived gateway monitor process. The FS-backed store
483
- * bridges those two processes. The in-memory store is also populated so
484
- * same-process flows keep the fast path.
485
- */
454
+ /** Persist consent bytes for callbacks received by another process after the CLI exits. */
486
455
  async function prepareFileConsentActivityFs(params) {
487
- const { media, conversationId, description } = params;
488
- const upload = {
489
- buffer: media.buffer,
490
- filename: media.filename,
491
- contentType: media.contentType,
492
- conversationId
493
- };
494
- const uploadId = storePendingUpload(upload);
456
+ const result = prepareFileConsentActivity(params);
495
457
  await storePendingUploadFs({
496
- id: uploadId,
497
- ...upload
458
+ id: result.uploadId,
459
+ ...params.media,
460
+ conversationId: params.conversationId
498
461
  });
499
- return {
500
- activity: buildConsentActivity({
501
- media,
502
- description,
503
- uploadId
504
- }),
505
- uploadId
506
- };
462
+ return result;
507
463
  }
508
464
  function requiresFileConsent(params) {
509
465
  const isPersonal = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeOptionalLowercaseString)(params.conversationType) === "personal";
510
466
  const isImage = params.contentType?.startsWith("image/") ?? false;
511
- const isLargeFile = params.bufferSize >= params.thresholdBytes;
467
+ const isLargeFile = params.bufferSize >= FILE_CONSENT_THRESHOLD_BYTES;
512
468
  return isPersonal && (isLargeFile || !isImage);
513
469
  }
514
470
  //#endregion
@@ -985,10 +941,7 @@ async function uploadAndShareSharePoint(params) {
985
941
  }
986
942
  //#endregion
987
943
  //#region extensions/msteams/src/media-helpers.ts
988
- /**
989
- * Detect MIME type from URL extension or data URL.
990
- * Uses shared MIME detection for consistency with core handling.
991
- */
944
+ const MSTEAMS_MAX_MEDIA_BYTES = 104857600;
992
945
  async function getMimeType(url) {
993
946
  if (url.startsWith("data:")) {
994
947
  const match = url.match(/^data:([^;,]+)/);
@@ -1027,9 +980,6 @@ async function extractFilename(url) {
1027
980
  function isLocalPath(url) {
1028
981
  return /^file:\/\//iu.test(url) || url.startsWith("/") || url.startsWith("~") || url.startsWith("\\") || /^[a-zA-Z]:[\\/]/.test(url);
1029
982
  }
1030
- /**
1031
- * Extract the message ID from a Bot Framework response.
1032
- */
1033
983
  function extractMessageId(response) {
1034
984
  if (!response || typeof response !== "object" || !("id" in response)) return null;
1035
985
  const { id } = response;
@@ -1052,14 +1002,10 @@ function isValidTeamsId(id) {
1052
1002
  return TEAMS_BOT_ID_PATTERN.test(id) || AAD_OBJECT_ID_PATTERN.test(id);
1053
1003
  }
1054
1004
  /**
1055
- * Parse mentions from text in the format @[Name](id).
1056
- * Example: "Hello @[John Doe](28:xxx-yyy-zzz)!"
1057
- *
1005
+ * Convert @[Name](id) into matching <at> text and mention entities.
1058
1006
  * Only matches where the id looks like a real Teams user/bot ID are treated
1059
1007
  * as mentions. This avoids false positives from documentation or code samples
1060
1008
  * embedded in the message (e.g. `@[表示名](ユーザーID)` in backticks).
1061
- *
1062
- * Returns both the formatted text with <at> tags and the entities array.
1063
1009
  */
1064
1010
  function parseMentions(text) {
1065
1011
  const mentionPattern = /@\[((?:\\[\s\S]|[^\]\\])+)\]\(([^)]+)\)/g;
@@ -1287,16 +1233,6 @@ async function deleteMSTeamsActivityWithReference(app, source, activityId, optio
1287
1233
  }
1288
1234
  //#endregion
1289
1235
  //#region extensions/msteams/src/messenger.ts
1290
- /**
1291
- * MSTeams-specific media size limit (100MB).
1292
- * Higher than the default to support Teams file-consent and SharePoint uploads.
1293
- */
1294
- const MSTEAMS_MAX_MEDIA_BYTES = 104857600;
1295
- /**
1296
- * Threshold for large files that require FileConsentCard flow in personal chats.
1297
- * Files >= 4MB use consent flow; smaller images can use inline base64.
1298
- */
1299
- const FILE_CONSENT_THRESHOLD_BYTES = 4194304;
1300
1236
  function buildConversationReference(ref) {
1301
1237
  const conversationId = ref.conversation?.id?.trim();
1302
1238
  if (!conversationId) throw new Error("Invalid stored reference: missing conversation.id");
@@ -1394,7 +1330,7 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1394
1330
  let contentType = await getMimeType(msg.mediaUrl);
1395
1331
  let fileName = await extractFilename(msg.mediaUrl);
1396
1332
  if (isLocalPath(msg.mediaUrl)) {
1397
- const maxBytes = mediaMaxBytes ?? MSTEAMS_MAX_MEDIA_BYTES;
1333
+ const maxBytes = mediaMaxBytes ?? 104857600;
1398
1334
  const media = await (0, openclaw_plugin_sdk_web_media.loadWebMedia)(msg.mediaUrl, maxBytes);
1399
1335
  contentType = media.contentType ?? contentType;
1400
1336
  fileName = media.fileName ?? fileName;
@@ -1404,8 +1340,7 @@ async function buildActivity(msg, conversationRef, tokenProvider, sharePointSite
1404
1340
  if (requiresFileConsent({
1405
1341
  conversationType,
1406
1342
  contentType,
1407
- bufferSize: media.buffer.length,
1408
- thresholdBytes: FILE_CONSENT_THRESHOLD_BYTES
1343
+ bufferSize: media.buffer.length
1409
1344
  })) {
1410
1345
  const conversationId = conversationRef.conversation?.id ?? "unknown";
1411
1346
  require_resolve_allowlist.assertMSTeamsSendHandoff(options);
@@ -1509,11 +1444,6 @@ async function sendMSTeamsMessages(params) {
1509
1444
  if (pendingUploadId && messageId !== "unknown") setPendingUploadActivityId(pendingUploadId, messageId);
1510
1445
  return messageId;
1511
1446
  };
1512
- const sendMessageBatchInContext = async (sendFn, batch, startIndex) => {
1513
- const messageIds = [];
1514
- for (const [idx, message] of batch.entries()) messageIds.push(await sendMessageInContext(sendFn, message, startIndex + idx));
1515
- return messageIds;
1516
- };
1517
1447
  const sendProactively = async (batch, startIndex, threadActivityId) => {
1518
1448
  let baseRef;
1519
1449
  try {
@@ -1529,7 +1459,9 @@ async function sendMSTeamsMessages(params) {
1529
1459
  threadActivityId: isChannel ? threadActivityId : void 0,
1530
1460
  serviceUrlBoundary: params.serviceUrlBoundary
1531
1461
  });
1532
- return await sendMessageBatchInContext(sendFn, batch, startIndex);
1462
+ const messageIds = [];
1463
+ for (const [idx, message] of batch.entries()) messageIds.push(await sendMessageInContext(sendFn, message, startIndex + idx));
1464
+ return messageIds;
1533
1465
  };
1534
1466
  const resolvedThreadId = params.conversationRef.threadId ?? params.conversationRef.activityId;
1535
1467
  if (params.replyStyle === "thread") {
@@ -1636,7 +1568,7 @@ function buildMSTeamsPollCard(params) {
1636
1568
  title: option,
1637
1569
  value: String(index)
1638
1570
  }));
1639
- const hint = cappedMaxSelections > 1 ? `Select up to ${cappedMaxSelections} option${cappedMaxSelections === 1 ? "" : "s"}.` : "Select one option.";
1571
+ const hint = cappedMaxSelections > 1 ? `Select up to ${cappedMaxSelections} options.` : "Select one option.";
1640
1572
  const card = {
1641
1573
  type: "AdaptiveCard",
1642
1574
  version: "1.5",
@@ -1841,12 +1773,6 @@ function createMSTeamsPollStoreState(params) {
1841
1773
  }
1842
1774
  //#endregion
1843
1775
  //#region extensions/msteams/src/conversation-store-helpers.ts
1844
- function toConversationStoreEntries(entries) {
1845
- return Array.from(entries, ([conversationId, reference]) => ({
1846
- conversationId,
1847
- reference
1848
- }));
1849
- }
1850
1776
  function mergeStoredConversationReference(existing, incoming, nowIso) {
1851
1777
  return {
1852
1778
  ...existing?.timezone && !incoming.timezone ? { timezone: existing.timezone } : {},
@@ -1859,18 +1785,22 @@ function mergeStoredConversationReference(existing, incoming, nowIso) {
1859
1785
  function findPreferredDmConversationByUserId(entries, id) {
1860
1786
  const target = id.trim();
1861
1787
  if (!target) return null;
1862
- const personalMatches = [];
1863
- const unknownTypeMatches = [];
1788
+ let preferred = null;
1789
+ let preferredIsPersonal = false;
1790
+ let preferredTimestamp = 0;
1864
1791
  for (const entry of entries) {
1865
1792
  if (entry.reference.user?.aadObjectId !== target && entry.reference.user?.id !== target) continue;
1866
1793
  const convType = (0, openclaw_plugin_sdk_string_coerce_runtime.normalizeLowercaseStringOrEmpty)(entry.reference.conversation?.conversationType ?? "");
1867
- if (convType === "personal") personalMatches.push(entry);
1868
- else if (convType === "channel" || convType === "groupchat") {} else unknownTypeMatches.push(entry);
1794
+ if (convType === "channel" || convType === "groupchat") continue;
1795
+ const isPersonal = convType === "personal";
1796
+ const timestamp = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(entry.reference.lastSeenAt) ?? 0;
1797
+ if (!preferred || isPersonal && !preferredIsPersonal || isPersonal === preferredIsPersonal && timestamp > preferredTimestamp) {
1798
+ preferred = entry;
1799
+ preferredIsPersonal = isPersonal;
1800
+ preferredTimestamp = timestamp;
1801
+ }
1869
1802
  }
1870
- const candidates = personalMatches.length > 0 ? personalMatches : unknownTypeMatches;
1871
- if (candidates.length === 0) return null;
1872
- if (candidates.length > 1) candidates.sort((a, b) => ((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(b.reference.lastSeenAt) ?? 0) - ((0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(a.reference.lastSeenAt) ?? 0));
1873
- return candidates[0] ?? null;
1803
+ return preferred;
1874
1804
  }
1875
1805
  //#endregion
1876
1806
  //#region extensions/msteams/src/conversation-store-state.ts
@@ -1879,32 +1809,20 @@ const MSTEAMS_MAX_CONVERSATIONS = 1e3;
1879
1809
  const MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS = 2e3;
1880
1810
  const MSTEAMS_CONVERSATION_TTL_MS = 31536e6;
1881
1811
  const CONVERSATION_MUTATION_KEY = "conversations";
1882
- function createConversationStateStore(params) {
1883
- return require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1884
- namespace: MSTEAMS_CONVERSATIONS_NAMESPACE,
1885
- maxEntries: MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS,
1886
- env: resolveMSTeamsSqliteStateEnv(params)
1887
- });
1888
- }
1889
1812
  function buildMSTeamsConversationStateKey(conversationId) {
1890
1813
  return node_crypto.default.createHash("sha256").update(conversationId).digest("hex");
1891
1814
  }
1892
- function prepareMSTeamsConversationReferenceForStorage(conversationId, reference) {
1893
- return {
1894
- ...reference,
1895
- conversation: {
1896
- ...reference.conversation,
1897
- id: conversationId
1898
- }
1899
- };
1900
- }
1901
1815
  function getStoredConversationId(reference) {
1902
1816
  const rawId = reference.conversation?.id;
1903
1817
  return rawId ? require_resolve_allowlist.normalizeMSTeamsConversationId(rawId) : null;
1904
1818
  }
1905
1819
  function createMSTeamsConversationStoreState(params) {
1906
1820
  const ttlMs = params?.ttlMs ?? MSTEAMS_CONVERSATION_TTL_MS;
1907
- const conversationStore = createConversationStateStore(params);
1821
+ const conversationStore = require_runtime.getMSTeamsRuntime().state.openKeyedStore({
1822
+ namespace: MSTEAMS_CONVERSATIONS_NAMESPACE,
1823
+ maxEntries: MSTEAMS_SQLITE_MAX_CONVERSATION_ROWS,
1824
+ env: resolveMSTeamsSqliteStateEnv(params)
1825
+ });
1908
1826
  const isExpired = (reference) => {
1909
1827
  const lastSeenAt = (0, openclaw_plugin_sdk_number_runtime.parseDateStringTimestampMs)(reference.lastSeenAt);
1910
1828
  return lastSeenAt != null && Date.now() - lastSeenAt > ttlMs;
@@ -1912,23 +1830,30 @@ function createMSTeamsConversationStoreState(params) {
1912
1830
  const lookupStored = async (conversationId) => {
1913
1831
  const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
1914
1832
  const value = await conversationStore.lookup(buildMSTeamsConversationStateKey(normalizedId));
1915
- if (!value) return null;
1916
- if (isExpired(value)) return null;
1917
- return value;
1833
+ return value && !isExpired(value) ? value : null;
1918
1834
  };
1919
- const entries = async () => {
1835
+ const list = async () => {
1920
1836
  const rows = await conversationStore.entries();
1921
1837
  const kept = [];
1922
1838
  for (const row of rows) {
1923
1839
  if (isExpired(row.value)) continue;
1924
1840
  const conversationId = getStoredConversationId(row.value);
1925
- if (conversationId) kept.push([conversationId, row.value]);
1841
+ if (conversationId) kept.push({
1842
+ conversationId,
1843
+ reference: row.value
1844
+ });
1926
1845
  }
1927
1846
  return kept;
1928
1847
  };
1929
1848
  const register = async (conversationId, reference) => {
1930
1849
  const normalizedId = require_resolve_allowlist.normalizeMSTeamsConversationId(conversationId);
1931
- await conversationStore.register(buildMSTeamsConversationStateKey(normalizedId), toPluginJsonValue(prepareMSTeamsConversationReferenceForStorage(normalizedId, reference)));
1850
+ await conversationStore.register(buildMSTeamsConversationStateKey(normalizedId), toPluginJsonValue({
1851
+ ...reference,
1852
+ conversation: {
1853
+ ...reference.conversation,
1854
+ id: normalizedId
1855
+ }
1856
+ }));
1932
1857
  const rows = [];
1933
1858
  for (const row of await conversationStore.entries()) {
1934
1859
  if (isExpired(row.value)) {
@@ -1947,9 +1872,6 @@ function createMSTeamsConversationStoreState(params) {
1947
1872
  });
1948
1873
  for (const row of sorted.slice(0, rows.length - MSTEAMS_MAX_CONVERSATIONS)) await conversationStore.delete(row.key);
1949
1874
  };
1950
- const list = async () => {
1951
- return toConversationStoreEntries(await entries());
1952
- };
1953
1875
  const findPreferredDmByUserId = async (id) => {
1954
1876
  return findPreferredDmConversationByUserId(await list(), id);
1955
1877
  };
@@ -1975,6 +1897,18 @@ function createMSTeamsConversationStoreState(params) {
1975
1897
  };
1976
1898
  }
1977
1899
  //#endregion
1900
+ Object.defineProperty(exports, "FILE_CONSENT_THRESHOLD_BYTES", {
1901
+ enumerable: true,
1902
+ get: function() {
1903
+ return FILE_CONSENT_THRESHOLD_BYTES;
1904
+ }
1905
+ });
1906
+ Object.defineProperty(exports, "MSTEAMS_MAX_MEDIA_BYTES", {
1907
+ enumerable: true,
1908
+ get: function() {
1909
+ return MSTEAMS_MAX_MEDIA_BYTES;
1910
+ }
1911
+ });
1978
1912
  Object.defineProperty(exports, "buildConversationReference", {
1979
1913
  enumerable: true,
1980
1914
  get: function() {