@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,9 +1,12 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-CEj9sABO.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
2
+ const require_config_schema = require("./config-schema-C4CszdDi.cjs");
2
3
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
3
- let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
4
4
  let openclaw_plugin_sdk_allow_from = require("openclaw/plugin-sdk/allow-from");
5
+ let openclaw_plugin_sdk_account_id = require("openclaw/plugin-sdk/account-id");
5
6
  let openclaw_plugin_sdk_number_runtime = require("openclaw/plugin-sdk/number-runtime");
6
7
  let openclaw_plugin_sdk_channel_config_helpers = require("openclaw/plugin-sdk/channel-config-helpers");
8
+ let openclaw_plugin_sdk_secret_file_runtime = require("openclaw/plugin-sdk/secret-file-runtime");
9
+ let openclaw_plugin_sdk_account_helpers = require("openclaw/plugin-sdk/account-helpers");
7
10
  let openclaw_plugin_sdk_channel_setup = require("openclaw/plugin-sdk/channel-setup");
8
11
  let openclaw_plugin_sdk_setup = require("openclaw/plugin-sdk/setup");
9
12
  let openclaw_plugin_sdk_setup_tools = require("openclaw/plugin-sdk/setup-tools");
@@ -20,13 +23,23 @@ const msteamsMeta = {
20
23
  aliases: ["teams"],
21
24
  order: 60
22
25
  };
26
+ function resolveMSTeamsAccount(cfg) {
27
+ const config = cfg.channels?.msteams;
28
+ const credentials = require_resolve_allowlist.resolveMSTeamsCredentials(config);
29
+ const certificatePath = credentials?.type === "federated" && !credentials.useManagedIdentity ? credentials.certificatePath : void 0;
30
+ 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;
31
+ const unavailable = certificate?.status === "configured_unavailable";
32
+ return {
33
+ accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
34
+ enabled: config?.enabled !== false,
35
+ configured: Boolean(credentials),
36
+ tokenStatus: !credentials ? "missing" : unavailable ? "configured_unavailable" : "available",
37
+ ...unavailable ? { credentialDiagnostics: [certificate.diagnostic] } : {}
38
+ };
39
+ }
23
40
  const msteamsConfigAdapter = (0, openclaw_plugin_sdk_channel_config_helpers.createTopLevelChannelConfigAdapter)({
24
41
  sectionKey: "msteams",
25
- resolveAccount: (cfg) => ({
26
- accountId: openclaw_plugin_sdk_account_id.DEFAULT_ACCOUNT_ID,
27
- enabled: cfg.channels?.msteams?.enabled !== false,
28
- configured: Boolean(require_resolve_allowlist.resolveMSTeamsCredentials(cfg.channels?.msteams))
29
- }),
42
+ resolveAccount: resolveMSTeamsAccount,
30
43
  resolveAccessorAccount: ({ cfg }) => ({
31
44
  allowFrom: cfg.channels?.msteams?.allowFrom,
32
45
  defaultTo: cfg.channels?.msteams?.defaultTo
@@ -93,8 +106,8 @@ function createMSTeamsSetupWizardBase() {
93
106
  let appPassword = null;
94
107
  let tenantId = null;
95
108
  if (!resolved && !hasConfigCreds) await noteMSTeamsCredentialHelp(prompter);
96
- if (canUseEnv) if (await prompter.confirm({
97
- message: t$1("wizard.msteams.envPrompt"),
109
+ if (canUseEnv || hasConfigCreds) if (await prompter.confirm({
110
+ message: t$1(canUseEnv ? "wizard.msteams.envPrompt" : "wizard.msteams.credentialsKeep"),
98
111
  initialValue: true
99
112
  })) next = msteamsSetupAdapter.applyAccountConfig({
100
113
  cfg: next,
@@ -102,12 +115,7 @@ function createMSTeamsSetupWizardBase() {
102
115
  input: {}
103
116
  });
104
117
  else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
105
- else if (hasConfigCreds) {
106
- if (!await prompter.confirm({
107
- message: t$1("wizard.msteams.credentialsKeep"),
108
- initialValue: true
109
- })) ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
110
- } else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
118
+ else ({appId, appPassword, tenantId} = await promptMSTeamsCredentials(prompter));
111
119
  if (appId && appPassword && tenantId) next = {
112
120
  ...next,
113
121
  channels: {
@@ -225,12 +233,8 @@ function parseNonNegativeRetryAfterSeconds(raw) {
225
233
  });
226
234
  }
227
235
  /**
228
- * Classify outbound send errors for safe retries and actionable logs.
229
- *
230
- * Important: We only mark errors as retryable when we have an explicit HTTP
231
- * status code that indicates the message was not accepted (e.g. 429, 5xx).
232
- * For transport-level errors where delivery is ambiguous, we prefer to avoid
233
- * retries to reduce the chance of duplicate posts.
236
+ * Owns retry safety and delivery ambiguity for Teams send failures.
237
+ * Only Teams rate-limit rejection proves this unkeyed POST safe to replay.
234
238
  */
235
239
  function classifyMSTeamsSendError(err) {
236
240
  const statusCode = extractStatusCode(err);
@@ -254,15 +258,15 @@ function classifyMSTeamsSendError(err) {
254
258
  };
255
259
  }
256
260
  if (statusCode === 429) return {
257
- kind: "throttled",
261
+ kind: "replay-safe",
258
262
  statusCode,
259
263
  retryAfterMs: retryAfterMs ?? void 0,
260
264
  errorCode
261
265
  };
262
266
  if (statusCode === 408 || statusCode != null && statusCode >= 500) return {
263
- kind: "transient",
267
+ kind: "ambiguous",
268
+ source: "http",
264
269
  statusCode,
265
- retryAfterMs: retryAfterMs ?? void 0,
266
270
  errorCode
267
271
  };
268
272
  if (statusCode != null && statusCode >= 400) return {
@@ -270,17 +274,14 @@ function classifyMSTeamsSendError(err) {
270
274
  statusCode,
271
275
  errorCode
272
276
  };
273
- if (statusCode == null) {
274
- const networkCode = (0, openclaw_plugin_sdk_string_coerce_runtime.isRecord)(err) && typeof err.code === "string" ? err.code : null;
275
- if (networkCode === "ECONNREFUSED" || networkCode === "ENOTFOUND" || networkCode === "EHOSTUNREACH" || networkCode === "ETIMEDOUT" || networkCode === "ECONNRESET") return {
276
- kind: "network",
277
- errorCode: networkCode
278
- };
279
- }
277
+ if (statusCode == null && (0, openclaw_plugin_sdk_retry_runtime.isTransientNetworkError)(err)) return {
278
+ kind: "ambiguous",
279
+ source: "transport",
280
+ errorCode
281
+ };
280
282
  return {
281
283
  kind: "unknown",
282
284
  statusCode: statusCode ?? void 0,
283
- retryAfterMs: retryAfterMs ?? void 0,
284
285
  errorCode
285
286
  };
286
287
  }
@@ -299,9 +300,15 @@ function isRevokedProxyError(err) {
299
300
  function formatMSTeamsSendErrorHint(classification) {
300
301
  if (classification.kind === "auth") return "check msteams appId/appPassword/tenantId (or env vars MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID)";
301
302
  if (classification.errorCode === "ContentStreamNotAllowed") return "Teams expired the content stream; stop streaming earlier and fall back to normal message delivery";
302
- if (classification.kind === "throttled") return "Teams throttled the bot; backing off may help";
303
- if (classification.kind === "transient") return "transient Teams/Bot Framework error; retry may succeed";
304
- if (classification.kind === "network") return "transport-level failure sending reply to Teams Bot Connector (smba.trafficmanager.net) — check egress firewall rules allow outbound HTTPS to smba.trafficmanager.net";
303
+ if (classification.kind === "replay-safe") return "Teams throttled the bot; backing off may help";
304
+ if (classification.kind === "ambiguous") {
305
+ if (classification.source === "transport") return "transport-level failure sending to Teams Bot Connector (smba.trafficmanager.net); the outcome is unknown, so check egress and conversation history before taking further action";
306
+ return "Teams/Bot Framework delivery outcome is unknown; inspect the conversation history before taking further action";
307
+ }
308
+ }
309
+ function formatMSTeamsDeliveryFailureGuidance(classification) {
310
+ if (classification.kind === "replay-safe") return "The request was rate-limited before delivery; retrying later may succeed.";
311
+ if (classification.kind === "ambiguous") return "Delivery may already have succeeded; do not send the same content again without checking the conversation.";
305
312
  }
306
313
  //#endregion
307
314
  //#region extensions/msteams/src/setup-surface.ts
@@ -471,7 +478,7 @@ const msteamsSetupWizard = {
471
478
  };
472
479
  let oauthModule;
473
480
  try {
474
- oauthModule = await Promise.resolve().then(() => require("./oauth-CW6jVGp8.cjs"));
481
+ oauthModule = await Promise.resolve().then(() => require("./oauth-C9So7uld.cjs"));
475
482
  } catch (err) {
476
483
  await noteDelegatedAuthFailure(err);
477
484
  return {
@@ -525,6 +532,40 @@ const msteamsSetupWizard = {
525
532
  disable: (cfg) => (0, openclaw_plugin_sdk_setup.setSetupChannelEnabled)(cfg, channel, false)
526
533
  };
527
534
  //#endregion
535
+ //#region extensions/msteams/src/channel.setup.ts
536
+ const msteamsSetupPlugin = {
537
+ id: "msteams",
538
+ meta: {
539
+ ...msteamsMeta,
540
+ aliases: [...msteamsMeta.aliases]
541
+ },
542
+ capabilities: {
543
+ chatTypes: [
544
+ "direct",
545
+ "channel",
546
+ "group",
547
+ "thread"
548
+ ],
549
+ polls: true,
550
+ threads: true,
551
+ media: true,
552
+ reactions: true
553
+ },
554
+ reload: { configPrefixes: ["channels.msteams"] },
555
+ configSchema: require_config_schema.MSTeamsChannelConfigSchema,
556
+ config: {
557
+ ...msteamsConfigAdapter,
558
+ isConfigured: (account) => account.configured,
559
+ describeAccount: (account) => (0, openclaw_plugin_sdk_account_helpers.describeAccountSnapshot)({
560
+ account,
561
+ configured: account.configured,
562
+ extra: { tokenStatus: account.tokenStatus }
563
+ })
564
+ },
565
+ setupWizard: msteamsSetupWizard,
566
+ setupContract: msteamsSetupContract
567
+ };
568
+ //#endregion
528
569
  Object.defineProperty(exports, "classifyMSTeamsSendError", {
529
570
  enumerable: true,
530
571
  get: function() {
@@ -537,6 +578,12 @@ Object.defineProperty(exports, "createMSTeamsSetupWizardBase", {
537
578
  return createMSTeamsSetupWizardBase;
538
579
  }
539
580
  });
581
+ Object.defineProperty(exports, "formatMSTeamsDeliveryFailureGuidance", {
582
+ enumerable: true,
583
+ get: function() {
584
+ return formatMSTeamsDeliveryFailureGuidance;
585
+ }
586
+ });
540
587
  Object.defineProperty(exports, "formatMSTeamsSendErrorHint", {
541
588
  enumerable: true,
542
589
  get: function() {
@@ -555,28 +602,16 @@ Object.defineProperty(exports, "isRevokedProxyError", {
555
602
  return isRevokedProxyError;
556
603
  }
557
604
  });
558
- Object.defineProperty(exports, "msteamsConfigAdapter", {
559
- enumerable: true,
560
- get: function() {
561
- return msteamsConfigAdapter;
562
- }
563
- });
564
- Object.defineProperty(exports, "msteamsMeta", {
565
- enumerable: true,
566
- get: function() {
567
- return msteamsMeta;
568
- }
569
- });
570
605
  Object.defineProperty(exports, "msteamsSetupAdapter", {
571
606
  enumerable: true,
572
607
  get: function() {
573
608
  return msteamsSetupAdapter;
574
609
  }
575
610
  });
576
- Object.defineProperty(exports, "msteamsSetupContract", {
611
+ Object.defineProperty(exports, "msteamsSetupPlugin", {
577
612
  enumerable: true,
578
613
  get: function() {
579
- return msteamsSetupContract;
614
+ return msteamsSetupPlugin;
580
615
  }
581
616
  });
582
617
  Object.defineProperty(exports, "msteamsSetupWizard", {
@@ -591,3 +626,9 @@ Object.defineProperty(exports, "openDelegatedOAuthUrl", {
591
626
  return openDelegatedOAuthUrl;
592
627
  }
593
628
  });
629
+ Object.defineProperty(exports, "resolveMSTeamsAccount", {
630
+ enumerable: true,
631
+ get: function() {
632
+ return resolveMSTeamsAccount;
633
+ }
634
+ });
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_resolve_allowlist = require("./resolve-allowlist-CEj9sABO.cjs");
2
+ const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
3
3
  let openclaw_plugin_sdk_directory_runtime = require("openclaw/plugin-sdk/directory-runtime");
4
4
  const msteamsDirectoryContractPlugin = {
5
5
  id: "msteams",
@@ -1,18 +1,18 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_polls = require("./polls-BWKNpBSg.cjs");
2
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
3
3
  const require_delegated_state = require("./delegated-state-DiEz9JIa.cjs");
4
- const require_sso_token_store = require("./sso-token-store-TKYk_Ms7.cjs");
4
+ const require_polls = require("./polls-DvuJvaDG.cjs");
5
+ const require_sso_token_store = require("./sso-token-store-ChhO1f4i.cjs");
5
6
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
6
7
  let node_crypto = require("node:crypto");
7
- node_crypto = require_polls.__toESM(node_crypto, 1);
8
+ node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
8
9
  let node_fs_promises = require("node:fs/promises");
9
- node_fs_promises = require_polls.__toESM(node_fs_promises, 1);
10
+ node_fs_promises = require_rolldown_runtime.__toESM(node_fs_promises, 1);
10
11
  let node_path = require("node:path");
11
- node_path = require_polls.__toESM(node_path, 1);
12
- let openclaw_plugin_sdk_runtime_doctor = require("openclaw/plugin-sdk/runtime-doctor");
13
- let openclaw_plugin_sdk_session_store_runtime = require("openclaw/plugin-sdk/session-store-runtime");
12
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
13
+ let openclaw_plugin_sdk_runtime_doctor_migrations = require("openclaw/plugin-sdk/runtime-doctor-migrations");
14
14
  //#region extensions/msteams/doctor-contract-api.ts
15
- const streamingAliasMigration = (0, openclaw_plugin_sdk_runtime_doctor.defineChannelAliasMigration)({
15
+ const streamingAliasMigration = (0, openclaw_plugin_sdk_runtime_doctor_migrations.defineChannelAliasMigration)({
16
16
  channelId: "msteams",
17
17
  streaming: { defaultMode: "partial" }
18
18
  });
@@ -66,9 +66,10 @@ function listAgentIds(config) {
66
66
  for (const agent of config.agents?.list ?? []) if (typeof agent.id === "string" && agent.id.trim()) ids.add(agent.id.trim());
67
67
  return [...ids];
68
68
  }
69
- function listCandidateStorePaths(params) {
69
+ async function listCandidateStorePaths(params) {
70
+ const { resolveStorePath } = await import("openclaw/plugin-sdk/session-store-runtime");
70
71
  const paths = /* @__PURE__ */ new Set();
71
- for (const agentId of listAgentIds(params.config)) paths.add((0, openclaw_plugin_sdk_session_store_runtime.resolveStorePath)(params.config.session?.store, {
72
+ for (const agentId of listAgentIds(params.config)) paths.add(resolveStorePath(params.config.session?.store, {
72
73
  agentId,
73
74
  env: params.env
74
75
  }));
@@ -193,7 +194,7 @@ const stateMigrations = [
193
194
  if (await store.registerIfAbsent(require_polls.buildMSTeamsConversationStateKey(conversationId), require_polls.prepareMSTeamsConversationReferenceForStorage(conversationId, reference))) imported++;
194
195
  }
195
196
  changes.push(`Migrated ${imported} ${MSTEAMS_PLUGIN_ID} conversation ${imported === 1 ? "entry" : "entries"} -> plugin state`);
196
- await (0, openclaw_plugin_sdk_runtime_doctor.archiveLegacyStateSource)({
197
+ await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
197
198
  filePath,
198
199
  label: `${MSTEAMS_PLUGIN_ID} conversation`,
199
200
  changes,
@@ -259,7 +260,7 @@ const stateMigrations = [
259
260
  if (didImportPoll || importedVoteBucket) imported++;
260
261
  }
261
262
  changes.push(`Migrated ${imported} ${MSTEAMS_PLUGIN_ID} poll ${imported === 1 ? "entry" : "entries"} -> plugin state`);
262
- await (0, openclaw_plugin_sdk_runtime_doctor.archiveLegacyStateSource)({
263
+ await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
263
264
  filePath,
264
265
  label: `${MSTEAMS_PLUGIN_ID} poll`,
265
266
  changes,
@@ -304,7 +305,7 @@ const stateMigrations = [
304
305
  }
305
306
  changes.push(`Migrated ${imported} ${MSTEAMS_PLUGIN_ID} SSO token ${imported === 1 ? "entry" : "entries"} -> plugin state`);
306
307
  if (skipped > 0) warnings.push(`Skipped ${skipped} malformed ${MSTEAMS_PLUGIN_ID} SSO token ${skipped === 1 ? "entry" : "entries"} during migration`);
307
- await (0, openclaw_plugin_sdk_runtime_doctor.archiveLegacyStateSource)({
308
+ await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
308
309
  filePath,
309
310
  label: `${MSTEAMS_PLUGIN_ID} SSO-token`,
310
311
  changes,
@@ -383,7 +384,7 @@ const stateMigrations = [
383
384
  };
384
385
  }
385
386
  changes.push(`Migrated ${MSTEAMS_PLUGIN_ID} delegated OAuth token -> plugin state`);
386
- await (0, openclaw_plugin_sdk_runtime_doctor.archiveLegacyStateSource)({
387
+ await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
387
388
  filePath,
388
389
  label: `${MSTEAMS_PLUGIN_ID} delegated OAuth token`,
389
390
  changes,
@@ -399,14 +400,14 @@ const stateMigrations = [
399
400
  id: "msteams-feedback-learnings-json-to-plugin-state",
400
401
  label: "Microsoft Teams feedback learnings",
401
402
  async detectLegacyState(params) {
402
- const files = (await Promise.all(listCandidateStorePaths(params).map((storePath) => listLegacyLearningFiles(storePath)))).flat();
403
+ const files = (await Promise.all((await listCandidateStorePaths(params)).map((storePath) => listLegacyLearningFiles(storePath)))).flat();
403
404
  if (files.length === 0) return null;
404
405
  return { preview: [`- Microsoft Teams feedback learnings: ${files.length} ${files.length === 1 ? "file" : "files"} -> plugin state (${LEARNINGS_NAMESPACE})`] };
405
406
  },
406
407
  async migrateLegacyState(params) {
407
408
  const changes = [];
408
409
  const warnings = [];
409
- const files = (await Promise.all(listCandidateStorePaths(params).map((storePath) => listLegacyLearningFiles(storePath)))).flat();
410
+ const files = (await Promise.all((await listCandidateStorePaths(params)).map((storePath) => listLegacyLearningFiles(storePath)))).flat();
410
411
  const store = params.context.openPluginStateKeyedStore({
411
412
  namespace: LEARNINGS_NAMESPACE,
412
413
  maxEntries: MAX_LEARNING_ENTRIES
@@ -436,7 +437,7 @@ const stateMigrations = [
436
437
  updatedAt: Date.now()
437
438
  });
438
439
  imported++;
439
- await (0, openclaw_plugin_sdk_runtime_doctor.archiveLegacyStateSource)({
440
+ await (0, openclaw_plugin_sdk_runtime_doctor_migrations.archiveLegacyStateSource)({
440
441
  filePath: file.filePath,
441
442
  label: "Microsoft Teams feedback-learning",
442
443
  changes,
@@ -1,23 +1,27 @@
1
- const require_polls = require("./polls-BWKNpBSg.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
2
2
  const require_runtime = require("./runtime-gZTAuFux.cjs");
3
3
  require("./runtime-api.cjs");
4
- const require_resolve_allowlist = require("./resolve-allowlist-CEj9sABO.cjs");
5
- const require_setup_surface = require("./setup-surface-ByWjaXEn.cjs");
4
+ const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
5
+ const require_channel_setup = require("./channel.setup-mOFtsfYz.cjs");
6
+ const require_polls = require("./polls-DvuJvaDG.cjs");
6
7
  let openclaw_plugin_sdk_lazy_runtime = require("openclaw/plugin-sdk/lazy-runtime");
7
8
  let openclaw_plugin_sdk_string_coerce_runtime = require("openclaw/plugin-sdk/string-coerce-runtime");
9
+ let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
8
10
  let openclaw_plugin_sdk_reply_payload = require("openclaw/plugin-sdk/reply-payload");
9
11
  let openclaw_plugin_sdk_text_chunking = require("openclaw/plugin-sdk/text-chunking");
10
- let openclaw_plugin_sdk_provider_http = require("openclaw/plugin-sdk/provider-http");
11
12
  let node_dns_promises = require("node:dns/promises");
12
13
  let openclaw_plugin_sdk_ssrf_policy = require("openclaw/plugin-sdk/ssrf-policy");
13
14
  let openclaw_plugin_sdk_text_utility_runtime = require("openclaw/plugin-sdk/text-utility-runtime");
14
15
  let openclaw_plugin_sdk_html_entity_runtime = require("openclaw/plugin-sdk/html-entity-runtime");
16
+ let openclaw_plugin_sdk_retry_runtime = require("openclaw/plugin-sdk/retry-runtime");
15
17
  let node_crypto = require("node:crypto");
16
- node_crypto = require_polls.__toESM(node_crypto, 1);
18
+ node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
17
19
  let node_path = require("node:path");
18
- node_path = require_polls.__toESM(node_path, 1);
20
+ node_path = require_rolldown_runtime.__toESM(node_path, 1);
21
+ let openclaw_plugin_sdk_global_singleton = require("openclaw/plugin-sdk/global-singleton");
19
22
  let openclaw_plugin_sdk_error_runtime = require("openclaw/plugin-sdk/error-runtime");
20
23
  let openclaw_plugin_sdk_reply_chunking = require("openclaw/plugin-sdk/reply-chunking");
24
+ let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
21
25
  let openclaw_plugin_sdk_web_media = require("openclaw/plugin-sdk/web-media");
22
26
  let openclaw_plugin_sdk_media_runtime = require("openclaw/plugin-sdk/media-runtime");
23
27
  //#region extensions/msteams/src/graph-thread.ts
@@ -449,9 +453,15 @@ async function setPendingUploadActivityIdFs(id, activityId, options) {
449
453
  * before upload. This module stores the file data temporarily until the user
450
454
  * accepts or declines, or until the TTL expires.
451
455
  */
452
- const pendingUploads = /* @__PURE__ */ new Map();
453
- /** Timer handles keyed by upload ID, cleared on explicit removal to prevent ghost cleanup */
454
- const pendingUploadTimers = /* @__PURE__ */ new Map();
456
+ const { pendingUploads, pendingUploadTimers } = (0, openclaw_plugin_sdk_global_singleton.resolveGlobalSingleton)(Symbol.for("openclaw.msteams.pendingUploadState"), () => ({
457
+ pendingUploads: /* @__PURE__ */ new Map(),
458
+ /** Timer handles keyed by upload ID, cleared on explicit removal to prevent ghost cleanup. */
459
+ pendingUploadTimers: /* @__PURE__ */ new Map()
460
+ }), (state) => {
461
+ for (const timer of state.pendingUploadTimers.values()) clearTimeout(timer);
462
+ state.pendingUploadTimers.clear();
463
+ state.pendingUploads.clear();
464
+ });
455
465
  /** TTL for pending uploads: 5 minutes */
456
466
  const PENDING_UPLOAD_TTL_MS = 300 * 1e3;
457
467
  /**
@@ -1088,13 +1098,14 @@ async function getGraphAccessToken(tokenProvider) {
1088
1098
  async function uploadToSharePoint(params) {
1089
1099
  const fetchFn = params.fetchFn ?? fetch;
1090
1100
  const uploadPath = `/OpenClawShared/${encodeURIComponent(params.filename)}`;
1101
+ const uploadUrl = `${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content?@microsoft.graph.conflictBehavior=rename`;
1091
1102
  const timeoutMs = require_resolve_allowlist.resolveMSTeamsSharePointUploadTimeoutMs(params.buffer.length);
1092
1103
  const data = await require_resolve_allowlist.withMSTeamsAbortableRequestTimeout({
1093
1104
  label: SHAREPOINT_UPLOAD_TIMEOUT_LABEL,
1094
1105
  timeoutMs,
1095
1106
  work: async (signal) => {
1096
1107
  const token = await getGraphAccessToken(params.tokenProvider);
1097
- const res = await fetchFn(`${GRAPH_ROOT}/sites/${params.siteId}/drive/root:${uploadPath}:/content`, {
1108
+ const res = await fetchFn(uploadUrl, {
1098
1109
  method: "PUT",
1099
1110
  headers: {
1100
1111
  "User-Agent": require_resolve_allowlist.buildUserAgent(),
@@ -1297,7 +1308,7 @@ async function extractFilename(url) {
1297
1308
  * Check if a URL refers to a local file path.
1298
1309
  */
1299
1310
  function isLocalPath(url) {
1300
- if (url.startsWith("file://") || url.startsWith("/") || url.startsWith("~")) return true;
1311
+ if (/^file:\/\//iu.test(url) || url.startsWith("/") || url.startsWith("~")) return true;
1301
1312
  if (url.startsWith("\\") && !url.startsWith("\\\\")) return true;
1302
1313
  if (/^[a-zA-Z]:[\\/]/.test(url)) return true;
1303
1314
  if (url.startsWith("\\\\")) return true;
@@ -1314,6 +1325,15 @@ function extractMessageId(response) {
1314
1325
  return id;
1315
1326
  }
1316
1327
  //#endregion
1328
+ //#region extensions/msteams/src/ai-entity.ts
1329
+ /** AI-generated content entity added to every outbound AI message. */
1330
+ const AI_GENERATED_ENTITY = {
1331
+ type: "https://schema.org/Message",
1332
+ "@type": "Message",
1333
+ "@id": "",
1334
+ additionalType: ["AIGeneratedContent"]
1335
+ };
1336
+ //#endregion
1317
1337
  //#region extensions/msteams/src/mentions.ts
1318
1338
  /**
1319
1339
  * Check whether an ID looks like a valid Teams user/bot identifier.
@@ -1367,14 +1387,21 @@ async function withRevokedProxyFallback(params) {
1367
1387
  try {
1368
1388
  return await params.run();
1369
1389
  } catch (err) {
1370
- if (!require_setup_surface.isRevokedProxyError(err)) throw err;
1390
+ if (!require_channel_setup.isRevokedProxyError(err)) throw err;
1371
1391
  params.onRevokedLog?.();
1372
1392
  return await params.onRevoked();
1373
1393
  }
1374
1394
  }
1375
1395
  //#endregion
1376
1396
  //#region extensions/msteams/src/sdk-proactive.ts
1377
- const loadMSTeamsApiModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api"));
1397
+ const loadMSTeamsApiClient = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api").then((api) => ({ Client: api.Client })));
1398
+ const loadMSTeamsQuoteModule = (0, openclaw_plugin_sdk_lazy_runtime.createLazyRuntimeModule)(() => import("@microsoft/teams.api/dist/activities/message/message.js").then((message) => ({ MessageActivityInput: message.MessageActivityInput })));
1399
+ async function quoteMSTeamsActivity(activity, messageId) {
1400
+ const { MessageActivityInput } = await loadMSTeamsQuoteModule();
1401
+ if (typeof activity === "string") return new MessageActivityInput(activity).prependQuote(messageId);
1402
+ if (activity.type !== "message") return activity;
1403
+ return MessageActivityInput.from(activity).prependQuote(messageId);
1404
+ }
1378
1405
  function resolveThreadedConversationId(conversationId, threadActivityId) {
1379
1406
  if (!threadActivityId) return conversationId.split(";")[0] ?? conversationId;
1380
1407
  return `${conversationId.split(";")[0] ?? conversationId};messageid=${threadActivityId}`;
@@ -1439,7 +1466,7 @@ async function getApiClientForReference(app, ref) {
1439
1466
  const appInternals = app;
1440
1467
  const httpClient = appInternals.api?.http ?? appInternals.client;
1441
1468
  if (!httpClient) return api;
1442
- const { Client } = await loadMSTeamsApiModule();
1469
+ const { Client } = await loadMSTeamsApiClient();
1443
1470
  return new Client(ref.serviceUrl, httpClient);
1444
1471
  }
1445
1472
  function mergeReferenceIntoActivity(activity, ref) {
@@ -1472,7 +1499,7 @@ function mergeReferenceIntoActivity(activity, ref) {
1472
1499
  async function sendMSTeamsActivityWithReference(app, source, activity, options) {
1473
1500
  const ref = buildSdkConversationReference(source, options);
1474
1501
  const activities = (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id);
1475
- const activityWithRef = mergeReferenceIntoActivity(activity, ref);
1502
+ const activityWithRef = mergeReferenceIntoActivity(options?.quoteActivityId ? await quoteMSTeamsActivity(activity, options.quoteActivityId) : activity, ref);
1476
1503
  const isTargeted = activityWithRef.recipient?.isTargeted === true;
1477
1504
  if (isTargeted && ref.conversation.conversationType === "personal") throw new Error("Targeted messages are not supported in 1:1 (personal) chats.");
1478
1505
  const activityId = typeof activityWithRef.id === "string" ? activityWithRef.id : void 0;
@@ -1498,15 +1525,6 @@ async function deleteMSTeamsActivityWithReference(app, source, activityId, optio
1498
1525
  return (await getApiClientForReference(app, ref)).conversations.activities(ref.conversation.id).delete(activityId);
1499
1526
  }
1500
1527
  //#endregion
1501
- //#region extensions/msteams/src/ai-entity.ts
1502
- /** AI-generated content entity added to every outbound AI message. */
1503
- const AI_GENERATED_ENTITY = {
1504
- type: "https://schema.org/Message",
1505
- "@type": "Message",
1506
- "@id": "",
1507
- additionalType: ["AIGeneratedContent"]
1508
- };
1509
- //#endregion
1510
1528
  //#region extensions/msteams/src/messenger.ts
1511
1529
  /**
1512
1530
  * MSTeams-specific media size limit (100MB).
@@ -1582,12 +1600,9 @@ function resolveRetryOptions(retry) {
1582
1600
  };
1583
1601
  }
1584
1602
  function computeRetryDelayMs(attempt, classification, opts) {
1585
- if (classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
1603
+ if (classification.kind === "replay-safe" && classification.retryAfterMs != null) return clampMs(classification.retryAfterMs, opts.maxDelayMs);
1586
1604
  return clampMs(opts.baseDelayMs * 2 ** Math.max(0, attempt - 1), opts.maxDelayMs);
1587
1605
  }
1588
- function shouldRetry(classification) {
1589
- return classification.kind === "throttled" || classification.kind === "transient";
1590
- }
1591
1606
  function renderReplyPayloadsToMessages(replies, options) {
1592
1607
  const out = [];
1593
1608
  const chunkLimit = Math.min(options.textChunkLimit, 4e3);
@@ -1711,24 +1726,24 @@ async function sendMSTeamsMessages(params) {
1711
1726
  const retryOptions = resolveRetryOptions(params.retry);
1712
1727
  const sendWithRetry = async (sendOnce, meta) => {
1713
1728
  if (!retryOptions.enabled) return await sendOnce();
1714
- for (const attempt of Array.from({ length: retryOptions.maxAttempts }, (_, index) => index + 1)) try {
1715
- return await sendOnce();
1716
- } catch (err) {
1717
- const classification = require_setup_surface.classifyMSTeamsSendError(err);
1718
- if (!(attempt < retryOptions.maxAttempts && shouldRetry(classification))) throw err;
1719
- const delayMs = computeRetryDelayMs(attempt, classification, retryOptions);
1720
- const nextAttempt = attempt + 1;
1721
- params.onRetry?.({
1722
- messageIndex: meta.messageIndex,
1723
- messageCount: meta.messageCount,
1724
- nextAttempt,
1725
- maxAttempts: retryOptions.maxAttempts,
1726
- delayMs,
1727
- classification
1728
- });
1729
- await (0, openclaw_plugin_sdk_text_utility_runtime.sleep)(delayMs);
1730
- }
1731
- throw new Error("unreachable Teams send retry loop exit");
1729
+ return await (0, openclaw_plugin_sdk_retry_runtime.retryAsync)(sendOnce, {
1730
+ attempts: retryOptions.maxAttempts,
1731
+ minDelayMs: 0,
1732
+ maxDelayMs: retryOptions.maxDelayMs,
1733
+ shouldRetry: (err) => require_channel_setup.classifyMSTeamsSendError(err).kind === "replay-safe",
1734
+ delayMs: ({ attempt, err }) => computeRetryDelayMs(attempt, require_channel_setup.classifyMSTeamsSendError(err), retryOptions),
1735
+ onRetry: ({ attempt, err, delayMs }) => {
1736
+ params.onRetry?.({
1737
+ messageIndex: meta.messageIndex,
1738
+ messageCount: meta.messageCount,
1739
+ nextAttempt: attempt + 1,
1740
+ maxAttempts: retryOptions.maxAttempts,
1741
+ delayMs,
1742
+ classification: require_channel_setup.classifyMSTeamsSendError(err)
1743
+ });
1744
+ },
1745
+ sleep: (delayMs) => (0, openclaw_plugin_sdk_runtime_env.sleepWithAbort)(delayMs)
1746
+ });
1732
1747
  };
1733
1748
  let providerDispatchStarted = false;
1734
1749
  const sendMessageInContext = async (sendFn, message, messageIndex) => {
@@ -1,14 +1,11 @@
1
- const require_resolve_allowlist = require("./resolve-allowlist-CEj9sABO.cjs");
1
+ const require_resolve_allowlist = require("./resolve-allowlist-CIfWUwuc.cjs");
2
+ let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
2
3
  let openclaw_plugin_sdk_provider_auth = require("openclaw/plugin-sdk/provider-auth");
3
4
  let openclaw_plugin_sdk_provider_auth_runtime = require("openclaw/plugin-sdk/provider-auth-runtime");
4
- let openclaw_plugin_sdk_runtime_env = require("openclaw/plugin-sdk/runtime-env");
5
5
  //#region extensions/msteams/src/oauth.flow.ts
6
6
  function shouldUseManualOAuthFlow(isRemote) {
7
7
  return isRemote || (0, openclaw_plugin_sdk_runtime_env.isWSL2Sync)();
8
8
  }
9
- function generatePkce() {
10
- return (0, openclaw_plugin_sdk_provider_auth.generateHexPkceVerifierChallenge)();
11
- }
12
9
  function buildMSTeamsAuthUrl(params) {
13
10
  const scopes = params.scopes ?? require_resolve_allowlist.MSTEAMS_DEFAULT_DELEGATED_SCOPES;
14
11
  return `${require_resolve_allowlist.buildMSTeamsAuthEndpoint(params.tenantId)}?${new URLSearchParams({
@@ -22,24 +19,6 @@ function buildMSTeamsAuthUrl(params) {
22
19
  prompt: "consent"
23
20
  }).toString()}`;
24
21
  }
25
- function parseCallbackInput(input, _expectedState) {
26
- return (0, openclaw_plugin_sdk_provider_auth_runtime.parseOAuthCallbackInput)(input, {
27
- missingState: "Missing 'state' parameter in URL. Paste the full redirect URL.",
28
- invalidInput: "Paste the full redirect URL (including code and state parameters), not just the authorization code."
29
- });
30
- }
31
- async function waitForLocalCallback(params) {
32
- return await (0, openclaw_plugin_sdk_provider_auth_runtime.waitForLocalOAuthCallback)({
33
- expectedState: params.expectedState,
34
- timeoutMs: params.timeoutMs,
35
- port: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PORT,
36
- callbackPath: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PATH,
37
- redirectUri: require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI,
38
- successTitle: "MSTeams Delegated OAuth complete",
39
- progressMessage: `Waiting for OAuth callback on ${require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI}...`,
40
- onProgress: params.onProgress
41
- });
42
- }
43
22
  //#endregion
44
23
  //#region extensions/msteams/src/oauth.ts
45
24
  async function loginMSTeamsDelegated(ctx, params) {
@@ -54,7 +33,7 @@ async function loginMSTeamsDelegated(ctx, params) {
54
33
  `Sign in to grant delegated permissions for MSTeams.`,
55
34
  `The callback will be captured automatically on localhost:${require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PORT}.`
56
35
  ].join("\n"), "MSTeams Delegated OAuth");
57
- const { verifier, challenge } = generatePkce();
36
+ const { verifier, challenge } = (0, openclaw_plugin_sdk_provider_auth.generateHexPkceVerifierChallenge)();
58
37
  const state = (0, openclaw_plugin_sdk_provider_auth_runtime.generateOAuthState)();
59
38
  const authUrl = buildMSTeamsAuthUrl({
60
39
  tenantId: params.tenantId,
@@ -71,9 +50,14 @@ async function loginMSTeamsDelegated(ctx, params) {
71
50
  ctx.log(`\nOpen this URL in your browser:\n\n${authUrl}\n`);
72
51
  }
73
52
  try {
74
- const { code } = await waitForLocalCallback({
53
+ const { code } = await (0, openclaw_plugin_sdk_provider_auth_runtime.waitForLocalOAuthCallback)({
75
54
  expectedState: state,
76
55
  timeoutMs: 300 * 1e3,
56
+ port: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PORT,
57
+ callbackPath: require_resolve_allowlist.MSTEAMS_OAUTH_CALLBACK_PATH,
58
+ redirectUri: require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI,
59
+ successTitle: "MSTeams Delegated OAuth complete",
60
+ progressMessage: `Waiting for OAuth callback on ${require_resolve_allowlist.MSTEAMS_OAUTH_REDIRECT_URI}...`,
77
61
  onProgress: (msg) => ctx.progress.update(msg)
78
62
  });
79
63
  ctx.progress.update("Exchanging authorization code for tokens...");
@@ -97,7 +81,10 @@ async function manualFlow(ctx, authUrl, state, verifier, params, cause) {
97
81
  ctx.progress.update("OAuth URL ready");
98
82
  ctx.log(`\nOpen this URL in your LOCAL browser:\n\n${authUrl}\n`);
99
83
  ctx.progress.update("Waiting for you to paste the callback URL...");
100
- const parsed = parseCallbackInput(await ctx.prompt("Paste the redirect URL here: "), state);
84
+ const parsed = (0, openclaw_plugin_sdk_provider_auth_runtime.parseOAuthCallbackInput)(await ctx.prompt("Paste the redirect URL here: "), {
85
+ missingState: "Missing 'state' parameter in URL. Paste the full redirect URL.",
86
+ invalidInput: "Paste the full redirect URL (including code and state parameters), not just the authorization code."
87
+ });
101
88
  if ("error" in parsed) throw new Error(parsed.error, cause ? { cause } : void 0);
102
89
  if (parsed.state !== state) throw new Error("OAuth state mismatch - please try again", cause ? { cause } : void 0);
103
90
  ctx.progress.update("Exchanging authorization code for tokens...");