diff --git a/extensions/browser/src/browser/chrome-mcp.runtime.ts b/extensions/browser/src/browser/chrome-mcp.runtime.ts new file mode 100644 index 00000000000..ec40536e4ee --- /dev/null +++ b/extensions/browser/src/browser/chrome-mcp.runtime.ts @@ -0,0 +1,5 @@ +export type ChromeMcpModule = typeof import("./chrome-mcp.js"); + +export async function getChromeMcpModule(): Promise { + return await import("./chrome-mcp.js"); +} diff --git a/extensions/browser/src/browser/server-context.availability.ts b/extensions/browser/src/browser/server-context.availability.ts index 541496bf402..e72cab21a3f 100644 --- a/extensions/browser/src/browser/server-context.availability.ts +++ b/extensions/browser/src/browser/server-context.availability.ts @@ -8,11 +8,7 @@ import { resolveCdpReachabilityTimeouts, } from "./cdp-timeouts.js"; import { redactCdpUrl } from "./cdp.helpers.js"; -import { - closeChromeMcpSession, - ensureChromeMcpAvailable, - listChromeMcpTabs, -} from "./chrome-mcp.js"; +import { getChromeMcpModule } from "./chrome-mcp.runtime.js"; import { diagnoseChromeCdp, formatChromeCdpDiagnostic, @@ -78,6 +74,7 @@ export function createProfileAvailability({ const isReachable = async (timeoutMs?: number) => { if (capabilities.usesChromeMcp) { // listChromeMcpTabs creates the session if needed — no separate ensureChromeMcpAvailable call required + const { listChromeMcpTabs } = await getChromeMcpModule(); await listChromeMcpTabs(profile.name, profile.userDataDir); return true; } @@ -155,6 +152,7 @@ export function createProfileAvailability({ setProfileRunning(null); } if (getBrowserProfileCapabilities(previousProfile).usesChromeMcp) { + const { closeChromeMcpSession } = await getChromeMcpModule(); await closeChromeMcpSession(previousProfile.name).catch(() => false); } await closePlaywrightBrowserConnectionForProfile(previousProfile.cdpUrl); @@ -191,6 +189,7 @@ export function createProfileAvailability({ let lastError: unknown; while (Date.now() < deadlineMs) { try { + const { listChromeMcpTabs } = await getChromeMcpModule(); await listChromeMcpTabs(profile.name, profile.userDataDir); return; } catch (err) { @@ -209,6 +208,7 @@ export function createProfileAvailability({ `Browser user data directory not found for profile "${profile.name}": ${profile.userDataDir}`, ); } + const { ensureChromeMcpAvailable } = await getChromeMcpModule(); await ensureChromeMcpAvailable(profile.name, profile.userDataDir); await waitForChromeMcpReadyAfterAttach(); return; @@ -308,6 +308,7 @@ export function createProfileAvailability({ const stopRunningBrowser = async (): Promise<{ stopped: boolean }> => { await reconcileProfileRuntime(); if (capabilities.usesChromeMcp) { + const { closeChromeMcpSession } = await getChromeMcpModule(); const stopped = await closeChromeMcpSession(profile.name); return { stopped }; } diff --git a/extensions/browser/src/browser/server-context.selection.ts b/extensions/browser/src/browser/server-context.selection.ts index 5a78e66bcbc..e17294dc046 100644 --- a/extensions/browser/src/browser/server-context.selection.ts +++ b/extensions/browser/src/browser/server-context.selection.ts @@ -2,7 +2,7 @@ import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime"; import type { SsrFPolicy } from "../infra/net/ssrf.js"; import { fetchOk, normalizeCdpHttpBaseForJsonEndpoints } from "./cdp.helpers.js"; import { appendCdpPath } from "./cdp.js"; -import { closeChromeMcpTab, focusChromeMcpTab } from "./chrome-mcp.js"; +import { getChromeMcpModule } from "./chrome-mcp.runtime.js"; import type { ResolvedBrowserProfile } from "./config.js"; import { BrowserTabNotFoundError, BrowserTargetAmbiguousError } from "./errors.js"; import { getBrowserProfileCapabilities } from "./profile-capabilities.js"; @@ -98,6 +98,7 @@ export function createProfileSelectionOps({ const resolvedTargetId = await resolveTargetIdOrThrow(targetId); if (capabilities.usesChromeMcp) { + const { focusChromeMcpTab } = await getChromeMcpModule(); await focusChromeMcpTab(profile.name, resolvedTargetId, profile.userDataDir); const profileState = getProfileState(); profileState.lastTargetId = resolvedTargetId; @@ -134,6 +135,7 @@ export function createProfileSelectionOps({ const resolvedTargetId = await resolveTargetIdOrThrow(targetId); if (capabilities.usesChromeMcp) { + const { closeChromeMcpTab } = await getChromeMcpModule(); await closeChromeMcpTab(profile.name, resolvedTargetId, profile.userDataDir); return; } diff --git a/extensions/browser/src/browser/server-context.tab-ops.ts b/extensions/browser/src/browser/server-context.tab-ops.ts index f91bcadb4cd..2909b82aee4 100644 --- a/extensions/browser/src/browser/server-context.tab-ops.ts +++ b/extensions/browser/src/browser/server-context.tab-ops.ts @@ -7,7 +7,7 @@ import { normalizeCdpHttpBaseForJsonEndpoints, } from "./cdp.helpers.js"; import { appendCdpPath, createTargetViaCdp, normalizeCdpWsUrl } from "./cdp.js"; -import { listChromeMcpTabs, openChromeMcpTab } from "./chrome-mcp.js"; +import { getChromeMcpModule } from "./chrome-mcp.runtime.js"; import type { ResolvedBrowserProfile } from "./config.js"; import { assertBrowserNavigationAllowed, @@ -74,6 +74,7 @@ export function createProfileTabOps({ const listTabs = async (): Promise => { if (capabilities.usesChromeMcp) { + const { listChromeMcpTabs } = await getChromeMcpModule(); return await listChromeMcpTabs(profile.name, profile.userDataDir); } @@ -155,6 +156,7 @@ export function createProfileTabOps({ if (capabilities.usesChromeMcp) { await assertBrowserNavigationAllowed({ url, ...ssrfPolicyOpts }); + const { openChromeMcpTab } = await getChromeMcpModule(); const page = await openChromeMcpTab(profile.name, url, profile.userDataDir); const profileState = getProfileState(); profileState.lastTargetId = page.targetId; diff --git a/extensions/msteams/src/attachments/graph.test.ts b/extensions/msteams/src/attachments/graph.test.ts index 6e2ad08a108..37f83b19841 100644 --- a/extensions/msteams/src/attachments/graph.test.ts +++ b/extensions/msteams/src/attachments/graph.test.ts @@ -20,7 +20,7 @@ vi.mock("./shared.js", async (importOriginal) => { }; }); -vi.mock("../../runtime-api.js", () => ({ +vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({ fetchWithSsrFGuard: vi.fn(), })); @@ -48,7 +48,7 @@ vi.mock("./remote-media.js", () => ({ downloadAndStoreMSTeamsRemoteMedia: vi.fn(), })); -import { fetchWithSsrFGuard } from "../../runtime-api.js"; +import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime"; import { downloadMSTeamsGraphMedia } from "./graph.js"; import { downloadAndStoreMSTeamsRemoteMedia } from "./remote-media.js"; import { safeFetchWithPolicy } from "./shared.js"; diff --git a/extensions/msteams/src/attachments/graph.ts b/extensions/msteams/src/attachments/graph.ts index a52b574bf26..ddb9b3149a4 100644 --- a/extensions/msteams/src/attachments/graph.ts +++ b/extensions/msteams/src/attachments/graph.ts @@ -1,9 +1,9 @@ +import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime"; import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, } from "openclaw/plugin-sdk/text-runtime"; -import { fetchWithSsrFGuard, type SsrFPolicy } from "../../runtime-api.js"; import { getMSTeamsRuntime } from "../runtime.js"; import { ensureUserAgentHeader } from "../user-agent.js"; import { downloadMSTeamsAttachments } from "./download.js"; diff --git a/extensions/msteams/src/messenger.ts b/extensions/msteams/src/messenger.ts index e74e165ddda..5b151c27794 100644 --- a/extensions/msteams/src/messenger.ts +++ b/extensions/msteams/src/messenger.ts @@ -1,15 +1,15 @@ -import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime"; import { - type ChunkMode, isSilentReplyText, - loadWebMedia, - type MarkdownTableMode, - type MSTeamsReplyStyle, - type ReplyPayload, - resolveSendableOutboundReplyParts, SILENT_REPLY_TOKEN, - sleep, -} from "../runtime-api.js"; + type ChunkMode, +} from "openclaw/plugin-sdk/reply-chunking"; +import { + resolveSendableOutboundReplyParts, + type ReplyPayload, +} from "openclaw/plugin-sdk/reply-payload"; +import { normalizeOptionalLowercaseString, sleep } from "openclaw/plugin-sdk/text-runtime"; +import { loadWebMedia } from "openclaw/plugin-sdk/web-media"; +import type { MarkdownTableMode, MSTeamsReplyStyle } 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.adaptive-card.test.ts b/extensions/msteams/src/monitor-handler.adaptive-card.test.ts index 09b2bb328f6..0a64298c13e 100644 --- a/extensions/msteams/src/monitor-handler.adaptive-card.test.ts +++ b/extensions/msteams/src/monitor-handler.adaptive-card.test.ts @@ -17,10 +17,8 @@ const runtimeApiMockState = vi.hoisted(() => ({ })), })); -vi.mock("../runtime-api.js", async () => { - const actual = await vi.importActual("../runtime-api.js"); +vi.mock("openclaw/plugin-sdk/inbound-reply-dispatch", () => { return { - ...actual, dispatchReplyFromConfigWithSettledDispatcher: runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher, }; diff --git a/extensions/msteams/src/monitor-handler/message-handler-mock-support.test-support.ts b/extensions/msteams/src/monitor-handler/message-handler-mock-support.test-support.ts index 2a673ca6be6..7666841db7c 100644 --- a/extensions/msteams/src/monitor-handler/message-handler-mock-support.test-support.ts +++ b/extensions/msteams/src/monitor-handler/message-handler-mock-support.test-support.ts @@ -12,11 +12,8 @@ export function getRuntimeApiMockState() { return runtimeApiMockState; } -vi.mock("../../runtime-api.js", async () => { - const actual = - await vi.importActual("../../runtime-api.js"); +vi.mock("openclaw/plugin-sdk/inbound-reply-dispatch", () => { return { - ...actual, dispatchReplyFromConfigWithSettledDispatcher: runtimeApiMockState.dispatchReplyFromConfigWithSettledDispatcher, }; diff --git a/extensions/msteams/src/monitor-handler/message-handler.ts b/extensions/msteams/src/monitor-handler/message-handler.ts index 587397abe91..79b3f030849 100644 --- a/extensions/msteams/src/monitor-handler/message-handler.ts +++ b/extensions/msteams/src/monitor-handler/message-handler.ts @@ -1,20 +1,24 @@ +import { formatAllowlistMatchMeta } from "openclaw/plugin-sdk/allow-from"; import { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound"; +import { + logInboundDrop, + resolveInboundSessionEnvelopeContext, +} from "openclaw/plugin-sdk/channel-inbound"; +import { resolveDualTextControlCommandGate } from "openclaw/plugin-sdk/command-gating"; +import { + filterSupplementalContextItems, + resolveChannelContextVisibilityMode, + shouldIncludeSupplementalContext, +} from "openclaw/plugin-sdk/context-visibility-runtime"; +import { evaluateSenderGroupAccessForPolicy } from "openclaw/plugin-sdk/group-access"; +import { dispatchReplyFromConfigWithSettledDispatcher } from "openclaw/plugin-sdk/inbound-reply-dispatch"; import { buildPendingHistoryContextFromMap, clearHistoryEntriesIfEnabled, - dispatchReplyFromConfigWithSettledDispatcher, DEFAULT_GROUP_HISTORY_LIMIT, - logInboundDrop, - evaluateSenderGroupAccessForPolicy, - filterSupplementalContextItems, recordPendingHistoryEntryIfEnabled, - resolveChannelContextVisibilityMode, - resolveDualTextControlCommandGate, - resolveInboundSessionEnvelopeContext, - shouldIncludeSupplementalContext, - formatAllowlistMatchMeta, type HistoryEntry, -} from "../../runtime-api.js"; +} from "openclaw/plugin-sdk/reply-history"; import { buildMSTeamsAttachmentPlaceholder, buildMSTeamsMediaPayload,