From 3cc83cb81ec30b7836e65f4e988c1233c903fa89 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 17 Mar 2026 20:06:54 -0700 Subject: [PATCH] Plugins: internalize msteams SDK imports --- AGENTS.md | 1 + extensions/msteams/runtime-api.ts | 1 + extensions/msteams/src/attachments/graph.ts | 2 +- extensions/msteams/src/attachments/payload.ts | 2 +- extensions/msteams/src/attachments/remote-media.ts | 2 +- extensions/msteams/src/attachments/shared.ts | 4 ++-- extensions/msteams/src/channel.ts | 8 ++------ extensions/msteams/src/directory-live.ts | 2 +- extensions/msteams/src/file-lock.ts | 2 +- extensions/msteams/src/graph.ts | 2 +- extensions/msteams/src/media-helpers.ts | 2 +- extensions/msteams/src/messenger.ts | 2 +- extensions/msteams/src/monitor-handler.ts | 2 +- extensions/msteams/src/monitor-handler/message-handler.ts | 2 +- extensions/msteams/src/monitor.ts | 2 +- extensions/msteams/src/outbound.ts | 2 +- extensions/msteams/src/policy.ts | 4 ++-- extensions/msteams/src/probe.ts | 2 +- extensions/msteams/src/reply-dispatcher.ts | 2 +- extensions/msteams/src/runtime.ts | 2 +- extensions/msteams/src/secret-input.ts | 2 +- extensions/msteams/src/send-context.ts | 2 +- extensions/msteams/src/send.ts | 4 ++-- extensions/msteams/src/setup-surface.ts | 2 +- extensions/msteams/src/store-fs.ts | 2 +- extensions/msteams/src/token.ts | 2 +- src/plugin-sdk/channel-import-guardrails.test.ts | 1 + 27 files changed, 31 insertions(+), 32 deletions(-) create mode 100644 extensions/msteams/runtime-api.ts diff --git a/AGENTS.md b/AGENTS.md index df72efbe720..57e7bd22100 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -114,6 +114,7 @@ - Never add `@ts-nocheck` and do not disable `no-explicit-any`; fix root causes and update Oxlint/Oxfmt config only when required. - Dynamic import guardrail: do not mix `await import("x")` and static `import ... from "x"` for the same module in production code paths. If you need lazy loading, create a dedicated `*.runtime.ts` boundary (that re-exports from `x`) and dynamically import that boundary from lazy callers only. - Dynamic import verification: after refactors that touch lazy-loading/module boundaries, run `pnpm build` and check for `[INEFFECTIVE_DYNAMIC_IMPORT]` warnings before submitting. +- Extension SDK self-import guardrail: inside an extension package, do not import that same extension via `openclaw/plugin-sdk/` from production files. Route internal imports through a local barrel such as `./api.ts` or `./runtime-api.ts`, and keep the `plugin-sdk/` path as the external contract only. - Never share class behavior via prototype mutation (`applyPrototypeMixins`, `Object.defineProperty` on `.prototype`, or exporting `Class.prototype` for merges). Use explicit inheritance/composition (`A extends B extends C`) or helper composition so TypeScript can typecheck. - If this pattern is needed, stop and get explicit approval before shipping; default behavior is to split/refactor into an explicit class hierarchy and keep members strongly typed. - In tests, prefer per-instance stubs over prototype mutation (`SomeClass.prototype.method = ...`) unless a test explicitly documents why prototype-level patching is required. diff --git a/extensions/msteams/runtime-api.ts b/extensions/msteams/runtime-api.ts new file mode 100644 index 00000000000..1347e49a695 --- /dev/null +++ b/extensions/msteams/runtime-api.ts @@ -0,0 +1 @@ +export * from "openclaw/plugin-sdk/msteams"; diff --git a/extensions/msteams/src/attachments/graph.ts b/extensions/msteams/src/attachments/graph.ts index 1798d438d1e..fca5f8d37a6 100644 --- a/extensions/msteams/src/attachments/graph.ts +++ b/extensions/msteams/src/attachments/graph.ts @@ -1,4 +1,4 @@ -import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/msteams"; +import { fetchWithSsrFGuard, type SsrFPolicy } from "../../runtime-api.js"; import { getMSTeamsRuntime } from "../runtime.js"; import { downloadMSTeamsAttachments } from "./download.js"; import { downloadAndStoreMSTeamsRemoteMedia } from "./remote-media.js"; diff --git a/extensions/msteams/src/attachments/payload.ts b/extensions/msteams/src/attachments/payload.ts index 8cfd79b29ce..c400b365d0d 100644 --- a/extensions/msteams/src/attachments/payload.ts +++ b/extensions/msteams/src/attachments/payload.ts @@ -1,4 +1,4 @@ -import { buildMediaPayload } from "openclaw/plugin-sdk/msteams"; +import { buildMediaPayload } from "../../runtime-api.js"; export function buildMSTeamsMediaPayload( mediaList: Array<{ path: string; contentType?: string }>, diff --git a/extensions/msteams/src/attachments/remote-media.ts b/extensions/msteams/src/attachments/remote-media.ts index 87c018b0290..e828dc9b1ce 100644 --- a/extensions/msteams/src/attachments/remote-media.ts +++ b/extensions/msteams/src/attachments/remote-media.ts @@ -1,4 +1,4 @@ -import type { SsrFPolicy } from "openclaw/plugin-sdk/msteams"; +import type { SsrFPolicy } from "../../runtime-api.js"; import { getMSTeamsRuntime } from "../runtime.js"; import { inferPlaceholder } from "./shared.js"; import type { MSTeamsInboundMedia } from "./types.js"; diff --git a/extensions/msteams/src/attachments/shared.ts b/extensions/msteams/src/attachments/shared.ts index cde483b0283..33af8077cd0 100644 --- a/extensions/msteams/src/attachments/shared.ts +++ b/extensions/msteams/src/attachments/shared.ts @@ -4,8 +4,8 @@ import { isHttpsUrlAllowedByHostnameSuffixAllowlist, isPrivateIpAddress, normalizeHostnameSuffixAllowlist, -} from "openclaw/plugin-sdk/msteams"; -import type { SsrFPolicy } from "openclaw/plugin-sdk/msteams"; +} from "../../runtime-api.js"; +import type { SsrFPolicy } from "../../runtime-api.js"; import type { MSTeamsAttachmentLike } from "./types.js"; type InlineImageCandidate = diff --git a/extensions/msteams/src/channel.ts b/extensions/msteams/src/channel.ts index 5f3a6aa0b59..77061d037de 100644 --- a/extensions/msteams/src/channel.ts +++ b/extensions/msteams/src/channel.ts @@ -6,11 +6,7 @@ import type { ChannelMessageToolDiscovery, } from "openclaw/plugin-sdk/channel-runtime"; import { createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime"; -import type { - ChannelMessageActionName, - ChannelPlugin, - OpenClawConfig, -} from "openclaw/plugin-sdk/msteams"; +import type { ChannelMessageActionName, ChannelPlugin, OpenClawConfig } from "../runtime-api.js"; import { buildProbeChannelStatusSummary, buildRuntimeAccountStatusSnapshot, @@ -19,7 +15,7 @@ import { DEFAULT_ACCOUNT_ID, MSTeamsConfigSchema, PAIRING_APPROVED_MESSAGE, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import { resolveMSTeamsGroupToolPolicy } from "./policy.js"; import type { ProbeMSTeamsResult } from "./probe.js"; import { diff --git a/extensions/msteams/src/directory-live.ts b/extensions/msteams/src/directory-live.ts index 66fbe16e876..df2ff6c35d0 100644 --- a/extensions/msteams/src/directory-live.ts +++ b/extensions/msteams/src/directory-live.ts @@ -1,4 +1,4 @@ -import type { ChannelDirectoryEntry } from "openclaw/plugin-sdk/msteams"; +import type { ChannelDirectoryEntry } from "../runtime-api.js"; import { searchGraphUsers } from "./graph-users.js"; import { type GraphChannel, diff --git a/extensions/msteams/src/file-lock.ts b/extensions/msteams/src/file-lock.ts index ef61d1b6214..fa3f4783cba 100644 --- a/extensions/msteams/src/file-lock.ts +++ b/extensions/msteams/src/file-lock.ts @@ -1 +1 @@ -export { withFileLock } from "openclaw/plugin-sdk/msteams"; +export { withFileLock } from "../runtime-api.js"; diff --git a/extensions/msteams/src/graph.ts b/extensions/msteams/src/graph.ts index 269216c7cd2..6100b197c03 100644 --- a/extensions/msteams/src/graph.ts +++ b/extensions/msteams/src/graph.ts @@ -1,4 +1,4 @@ -import type { MSTeamsConfig } from "openclaw/plugin-sdk/msteams"; +import type { MSTeamsConfig } from "../runtime-api.js"; import { GRAPH_ROOT } from "./attachments/shared.js"; import { loadMSTeamsSdkWithAuth } from "./sdk.js"; import { readAccessToken } from "./token-response.js"; diff --git a/extensions/msteams/src/media-helpers.ts b/extensions/msteams/src/media-helpers.ts index 8de456b8c39..4f9433c1e5c 100644 --- a/extensions/msteams/src/media-helpers.ts +++ b/extensions/msteams/src/media-helpers.ts @@ -8,7 +8,7 @@ import { extensionForMime, extractOriginalFilename, getFileExtension, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; /** * Detect MIME type from URL extension or data URL. diff --git a/extensions/msteams/src/messenger.ts b/extensions/msteams/src/messenger.ts index b45c39ac3fb..f03431391ed 100644 --- a/extensions/msteams/src/messenger.ts +++ b/extensions/msteams/src/messenger.ts @@ -7,7 +7,7 @@ import { type ReplyPayload, SILENT_REPLY_TOKEN, sleep, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import type { MSTeamsAccessTokenProvider } from "./attachments/types.js"; import type { StoredConversationReference } from "./conversation-store.js"; import { classifyMSTeamsSendError } from "./errors.js"; diff --git a/extensions/msteams/src/monitor-handler.ts b/extensions/msteams/src/monitor-handler.ts index bad810322a9..de586261568 100644 --- a/extensions/msteams/src/monitor-handler.ts +++ b/extensions/msteams/src/monitor-handler.ts @@ -1,4 +1,4 @@ -import type { OpenClawConfig, RuntimeEnv } from "openclaw/plugin-sdk/msteams"; +import type { OpenClawConfig, RuntimeEnv } from "../runtime-api.js"; import type { MSTeamsConversationStore } from "./conversation-store.js"; import { buildFileInfoCard, parseFileConsentInvoke, uploadToConsentUrl } from "./file-consent.js"; import { normalizeMSTeamsConversationId } from "./inbound.js"; diff --git a/extensions/msteams/src/monitor-handler/message-handler.ts b/extensions/msteams/src/monitor-handler/message-handler.ts index 60a88c56664..d07050062df 100644 --- a/extensions/msteams/src/monitor-handler/message-handler.ts +++ b/extensions/msteams/src/monitor-handler/message-handler.ts @@ -19,7 +19,7 @@ import { resolveEffectiveAllowFromLists, resolveDmGroupAccessWithLists, type HistoryEntry, -} from "openclaw/plugin-sdk/msteams"; +} from "../../runtime-api.js"; import { buildMSTeamsAttachmentPlaceholder, buildMSTeamsMediaPayload, diff --git a/extensions/msteams/src/monitor.ts b/extensions/msteams/src/monitor.ts index a889aa3d3bc..f5c60064174 100644 --- a/extensions/msteams/src/monitor.ts +++ b/extensions/msteams/src/monitor.ts @@ -7,7 +7,7 @@ import { summarizeMapping, type OpenClawConfig, type RuntimeEnv, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import { createMSTeamsConversationStoreFs } from "./conversation-store-fs.js"; import type { MSTeamsConversationStore } from "./conversation-store.js"; import { formatUnknownError } from "./errors.js"; diff --git a/extensions/msteams/src/outbound.ts b/extensions/msteams/src/outbound.ts index 8f56ab2ce4c..6334bb8c6b5 100644 --- a/extensions/msteams/src/outbound.ts +++ b/extensions/msteams/src/outbound.ts @@ -1,5 +1,5 @@ import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime"; -import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/msteams"; +import type { ChannelOutboundAdapter } from "../runtime-api.js"; import { createMSTeamsPollStoreFs } from "./polls.js"; import { getMSTeamsRuntime } from "./runtime.js"; import { sendMessageMSTeams, sendPollMSTeams } from "./send.js"; diff --git a/extensions/msteams/src/policy.ts b/extensions/msteams/src/policy.ts index c6317184d89..49479e1ce47 100644 --- a/extensions/msteams/src/policy.ts +++ b/extensions/msteams/src/policy.ts @@ -7,7 +7,7 @@ import type { MSTeamsConfig, MSTeamsReplyStyle, MSTeamsTeamConfig, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import { buildChannelKeyCandidates, evaluateSenderGroupAccessForPolicy, @@ -17,7 +17,7 @@ import { resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision, isDangerousNameMatchingEnabled, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; export type MSTeamsResolvedRouteConfig = { teamConfig?: MSTeamsTeamConfig; diff --git a/extensions/msteams/src/probe.ts b/extensions/msteams/src/probe.ts index 39bf82841c8..ce5f244c3dd 100644 --- a/extensions/msteams/src/probe.ts +++ b/extensions/msteams/src/probe.ts @@ -2,7 +2,7 @@ import { normalizeStringEntries, type BaseProbeResult, type MSTeamsConfig, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import { formatUnknownError } from "./errors.js"; import { loadMSTeamsSdkWithAuth } from "./sdk.js"; import { readAccessToken } from "./token-response.js"; diff --git a/extensions/msteams/src/reply-dispatcher.ts b/extensions/msteams/src/reply-dispatcher.ts index bf1e21f5e78..80540d9c527 100644 --- a/extensions/msteams/src/reply-dispatcher.ts +++ b/extensions/msteams/src/reply-dispatcher.ts @@ -6,7 +6,7 @@ import { type OpenClawConfig, type MSTeamsReplyStyle, type RuntimeEnv, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import type { MSTeamsAccessTokenProvider } from "./attachments/types.js"; import type { StoredConversationReference } from "./conversation-store.js"; import { diff --git a/extensions/msteams/src/runtime.ts b/extensions/msteams/src/runtime.ts index 016d12e9b29..5bbd3c5f9cd 100644 --- a/extensions/msteams/src/runtime.ts +++ b/extensions/msteams/src/runtime.ts @@ -1,5 +1,5 @@ -import type { PluginRuntime } from "openclaw/plugin-sdk/msteams"; import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store"; +import type { PluginRuntime } from "../runtime-api.js"; const { setRuntime: setMSTeamsRuntime, getRuntime: getMSTeamsRuntime } = createPluginRuntimeStore("MSTeams runtime not initialized"); diff --git a/extensions/msteams/src/secret-input.ts b/extensions/msteams/src/secret-input.ts index e2087fbc3c2..da9ca2993b7 100644 --- a/extensions/msteams/src/secret-input.ts +++ b/extensions/msteams/src/secret-input.ts @@ -2,6 +2,6 @@ import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; export { hasConfiguredSecretInput, normalizeResolvedSecretInputString, normalizeSecretInputString }; diff --git a/extensions/msteams/src/send-context.ts b/extensions/msteams/src/send-context.ts index d42d0c7d149..6b1b32fafa3 100644 --- a/extensions/msteams/src/send-context.ts +++ b/extensions/msteams/src/send-context.ts @@ -2,7 +2,7 @@ import { resolveChannelMediaMaxBytes, type OpenClawConfig, type PluginRuntime, -} from "openclaw/plugin-sdk/msteams"; +} from "../runtime-api.js"; import type { MSTeamsAccessTokenProvider } from "./attachments/types.js"; import { createMSTeamsConversationStoreFs } from "./conversation-store-fs.js"; import type { diff --git a/extensions/msteams/src/send.ts b/extensions/msteams/src/send.ts index 48fe0443a22..aaf6a8b4cc9 100644 --- a/extensions/msteams/src/send.ts +++ b/extensions/msteams/src/send.ts @@ -1,5 +1,5 @@ -import type { OpenClawConfig } from "openclaw/plugin-sdk/msteams"; -import { loadOutboundMediaFromUrl } from "openclaw/plugin-sdk/msteams"; +import type { OpenClawConfig } from "../runtime-api.js"; +import { loadOutboundMediaFromUrl } from "../runtime-api.js"; import { createMSTeamsConversationStoreFs } from "./conversation-store-fs.js"; import { classifyMSTeamsSendError, diff --git a/extensions/msteams/src/setup-surface.ts b/extensions/msteams/src/setup-surface.ts index 185bf3d7362..769e68cd58c 100644 --- a/extensions/msteams/src/setup-surface.ts +++ b/extensions/msteams/src/setup-surface.ts @@ -1,4 +1,3 @@ -import type { MSTeamsTeamConfig } from "openclaw/plugin-sdk/msteams"; import { DEFAULT_ACCOUNT_ID, formatDocsLink, @@ -13,6 +12,7 @@ import { type OpenClawConfig, type WizardPrompter, } from "openclaw/plugin-sdk/setup"; +import type { MSTeamsTeamConfig } from "../runtime-api.js"; import { parseMSTeamsTeamEntry, resolveMSTeamsChannelAllowlist, diff --git a/extensions/msteams/src/store-fs.ts b/extensions/msteams/src/store-fs.ts index 8f109914db1..8f032abfefc 100644 --- a/extensions/msteams/src/store-fs.ts +++ b/extensions/msteams/src/store-fs.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/msteams"; +import { readJsonFileWithFallback, writeJsonFileAtomically } from "../runtime-api.js"; import { withFileLock as withPathLock } from "./file-lock.js"; const STORE_LOCK_OPTIONS = { diff --git a/extensions/msteams/src/token.ts b/extensions/msteams/src/token.ts index 5f72ae444c1..31b43438986 100644 --- a/extensions/msteams/src/token.ts +++ b/extensions/msteams/src/token.ts @@ -1,4 +1,4 @@ -import type { MSTeamsConfig } from "openclaw/plugin-sdk/msteams"; +import type { MSTeamsConfig } from "../runtime-api.js"; import { hasConfiguredSecretInput, normalizeResolvedSecretInputString, diff --git a/src/plugin-sdk/channel-import-guardrails.test.ts b/src/plugin-sdk/channel-import-guardrails.test.ts index 5af6aeeb01a..24a70ec69f4 100644 --- a/src/plugin-sdk/channel-import-guardrails.test.ts +++ b/src/plugin-sdk/channel-import-guardrails.test.ts @@ -128,6 +128,7 @@ const LOCAL_EXTENSION_API_BARREL_GUARDS = [ "matrix", "mattermost", "memory-lancedb", + "msteams", "nextcloud-talk", "synology-chat", "talk-voice",