diff --git a/docs/plugins/architecture.md b/docs/plugins/architecture.md
index 5e771b0b796..9fba7fe34d9 100644
--- a/docs/plugins/architecture.md
+++ b/docs/plugins/architecture.md
@@ -473,7 +473,7 @@ Keep capability registration public. Trim non-contract helper exports:
- vendor-specific convenience helpers
- setup/onboarding helpers that are implementation details
-Some bundled-plugin helper subpaths still remain in the generated SDK export map for bundled-plugin maintenance when they have tracked owner usage. Current examples include `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`, `plugin-sdk/matrix-runtime-shared`, `plugin-sdk/github-copilot-token`, `plugin-sdk/memory-core`, `plugin-sdk/bundled-channel-config-schema`, and `plugin-sdk/channel-config-schema-legacy`. Treat those as reserved exports, not as the recommended SDK pattern for new third-party plugins.
+Reserved bundled-plugin helper subpaths have been retired from the generated SDK export map. Keep owner-specific helpers inside the owning plugin package; promote only reusable host behavior to generic SDK contracts such as `plugin-sdk/gateway-runtime`, `plugin-sdk/security-runtime`, and `plugin-sdk/plugin-config-runtime`.
## Internals and reference
diff --git a/docs/plugins/sdk-migration.md b/docs/plugins/sdk-migration.md
index 91551a1a7af..6c0d18933b3 100644
--- a/docs/plugins/sdk-migration.md
+++ b/docs/plugins/sdk-migration.md
@@ -544,23 +544,15 @@ This table is intentionally the common migration subset, not the full SDK
surface. The full list of 200+ entrypoints lives in
`scripts/lib/plugin-sdk-entrypoints.json`.
-That list still includes a few bundled-plugin helper seams that have tracked
-owner usage. They remain exported for bundled-plugin maintenance, but they are
-intentionally omitted from the common migration table and are not the
-recommended target for new plugin code.
-
-The same rule applies to other bundled-helper families such as:
-
-- browser support helpers: `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools`
-- Matrix: `plugin-sdk/matrix-runtime-shared`
-- bundled helper/plugin surfaces like `plugin-sdk/github-copilot-token` and `plugin-sdk/memory-core`
-
-`plugin-sdk/github-copilot-token` currently exposes the narrow token-helper
-surface `DEFAULT_COPILOT_API_BASE_URL`,
-`deriveCopilotApiBaseUrlFromToken`, and `resolveCopilotApiToken`.
+Reserved bundled-plugin helper seams have been retired from the public SDK
+export map. Owner-specific helpers live inside the owning plugin package; shared
+host behavior should move through generic SDK contracts such as
+`plugin-sdk/gateway-runtime`, `plugin-sdk/security-runtime`, and
+`plugin-sdk/plugin-config-runtime`.
Use the narrowest import that matches the job. If you cannot find an export,
-check the source at `src/plugin-sdk/` or ask in Discord.
+check the source at `src/plugin-sdk/` or ask maintainers which generic contract
+should own it.
## Active deprecations
diff --git a/docs/plugins/sdk-subpaths.md b/docs/plugins/sdk-subpaths.md
index 3bcf51c28d7..73710a12964 100644
--- a/docs/plugins/sdk-subpaths.md
+++ b/docs/plugins/sdk-subpaths.md
@@ -313,11 +313,10 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
- | Family | Current subpaths | Intended use |
- | --- | --- | --- |
- | Browser | `plugin-sdk/browser-config-runtime`, `plugin-sdk/browser-config-support`, `plugin-sdk/browser-node-runtime`, `plugin-sdk/browser-security-runtime`, `plugin-sdk/browser-setup-tools` | Bundled browser plugin support helpers still consumed by the owner package. |
- | Matrix | `plugin-sdk/matrix-runtime-shared` | Bundled Matrix runtime surface still consumed by the owner package. |
- | Auth/plugin-specific helpers | `plugin-sdk/github-copilot-token`, `plugin-sdk/memory-core` | Bundled feature/plugin helper seams still consumed by their owners; `plugin-sdk/github-copilot-token` currently exports `DEFAULT_COPILOT_API_BASE_URL`, `deriveCopilotApiBaseUrlFromToken`, and `resolveCopilotApiToken`. |
+ There are currently no reserved bundled-helper SDK subpaths. Owner-specific
+ helpers live inside the owning plugin package, while reusable host contracts
+ use generic SDK subpaths such as `plugin-sdk/gateway-runtime`,
+ `plugin-sdk/security-runtime`, and `plugin-sdk/plugin-config-runtime`.
diff --git a/extensions/browser/src/browser-tool.runtime.ts b/extensions/browser/src/browser-tool.runtime.ts
index 4d39ab21d7a..3896c876d39 100644
--- a/extensions/browser/src/browser-tool.runtime.ts
+++ b/extensions/browser/src/browser-tool.runtime.ts
@@ -1,4 +1,4 @@
-export { getRuntimeConfig } from "openclaw/plugin-sdk/browser-config-runtime";
+export { getRuntimeConfig } from "./sdk-config.js";
export {
callGatewayTool,
imageResultFromFile,
@@ -7,9 +7,9 @@ export {
readStringParam,
resolveNodeIdFromList,
selectDefaultNodeFromList,
-} from "openclaw/plugin-sdk/browser-setup-tools";
-export type { AnyAgentTool, NodeListNode } from "openclaw/plugin-sdk/browser-setup-tools";
-export { wrapExternalContent } from "openclaw/plugin-sdk/browser-security-runtime";
+} from "./sdk-setup-tools.js";
+export type { AnyAgentTool, NodeListNode } from "./sdk-setup-tools.js";
+export { wrapExternalContent } from "./sdk-security-runtime.js";
export { normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/text-runtime";
export { BrowserToolSchema } from "./browser-tool.schema.js";
export {
diff --git a/extensions/browser/src/browser-tool.test.ts b/extensions/browser/src/browser-tool.test.ts
index be941686fc1..5223fe78201 100644
--- a/extensions/browser/src/browser-tool.test.ts
+++ b/extensions/browser/src/browser-tool.test.ts
@@ -146,10 +146,9 @@ vi.mock("./browser/session-tab-registry.js", () => sessionTabRegistryMocks);
const toolCommonMocks = vi.hoisted(() => ({
imageResultFromFile: vi.fn(),
}));
-vi.mock("openclaw/plugin-sdk/browser-setup-tools", async () => {
- const actual = await vi.importActual(
- "openclaw/plugin-sdk/browser-setup-tools",
- );
+vi.mock("./sdk-setup-tools.js", async () => {
+ const actual =
+ await vi.importActual("./sdk-setup-tools.js");
return {
...actual,
callGatewayTool: gatewayMocks.callGatewayTool,
diff --git a/extensions/browser/src/browser/cdp.test.ts b/extensions/browser/src/browser/cdp.test.ts
index a68efdc27a6..dc3972d9138 100644
--- a/extensions/browser/src/browser/cdp.test.ts
+++ b/extensions/browser/src/browser/cdp.test.ts
@@ -5,7 +5,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { type WebSocket, WebSocketServer } from "ws";
import { SsrFBlockedError } from "../infra/net/ssrf.js";
import { rawDataToString } from "../infra/ws.js";
-import "../../test-support/browser-security-runtime.mock.js";
+import "../../test-support/browser-security.mock.js";
import {
isDirectCdpWebSocketEndpoint,
isWebSocketUrl,
diff --git a/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts b/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts
index da32f857657..3289601078e 100644
--- a/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts
+++ b/extensions/browser/src/browser/client-fetch.loopback-auth.test.ts
@@ -1,5 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
-import "../../test-support/browser-security-runtime.mock.js";
+import "../../test-support/browser-security.mock.js";
import type { OpenClawConfig } from "../config/config.js";
import type { BrowserDispatchResponse } from "./routes/dispatcher.js";
diff --git a/extensions/browser/src/browser/navigation-guard.ts b/extensions/browser/src/browser/navigation-guard.ts
index b9337ab6448..6d5749f89b5 100644
--- a/extensions/browser/src/browser/navigation-guard.ts
+++ b/extensions/browser/src/browser/navigation-guard.ts
@@ -1,14 +1,11 @@
import { isIP } from "node:net";
-import {
- matchesHostnameAllowlist,
- normalizeHostname,
-} from "openclaw/plugin-sdk/browser-security-runtime";
import {
isPrivateNetworkAllowedByPolicy,
resolvePinnedHostnameWithPolicy,
type LookupFn,
type SsrFPolicy,
} from "../infra/net/ssrf.js";
+import { matchesHostnameAllowlist, normalizeHostname } from "../sdk-security-runtime.js";
const NETWORK_NAVIGATION_PROTOCOLS = new Set(["http:", "https:"]);
const SAFE_NON_NETWORK_URLS = new Set(["about:blank"]);
diff --git a/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts b/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts
index adaffb6efd1..e52d4bf3b37 100644
--- a/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts
+++ b/extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.ts
@@ -1,7 +1,7 @@
import { chromium } from "playwright-core";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { SsrFBlockedError } from "../infra/net/ssrf.js";
-import "../../test-support/browser-security-runtime.mock.js";
+import "../../test-support/browser-security.mock.js";
import * as chromeModule from "./chrome.js";
import { BrowserTabNotFoundError } from "./errors.js";
import { InvalidBrowserNavigationUrlError } from "./navigation-guard.js";
diff --git a/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts b/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts
index 3569bae847f..8076c2d52bd 100644
--- a/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts
+++ b/extensions/browser/src/browser/pw-tools-core.snapshot.navigate-guard.test.ts
@@ -1,6 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { SsrFBlockedError } from "../infra/net/ssrf.js";
-import "../../test-support/browser-security-runtime.mock.js";
+import "../../test-support/browser-security.mock.js";
import { InvalidBrowserNavigationUrlError } from "./navigation-guard.js";
import {
getPwToolsCoreSessionMocks,
diff --git a/extensions/browser/src/browser/server-context.existing-session.test.ts b/extensions/browser/src/browser/server-context.existing-session.test.ts
index b6fb1f20283..007821d0c85 100644
--- a/extensions/browser/src/browser/server-context.existing-session.test.ts
+++ b/extensions/browser/src/browser/server-context.existing-session.test.ts
@@ -1,6 +1,6 @@
import fs from "node:fs";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
-import "../../test-support/browser-security-runtime.mock.js";
+import "../../test-support/browser-security.mock.js";
import type { BrowserServerState } from "./server-context.js";
const chromeMcpMock = vi.hoisted(() => ({
diff --git a/extensions/browser/src/cli/browser-cli-inspect.test.ts b/extensions/browser/src/cli/browser-cli-inspect.test.ts
index e428c60eab4..03944621020 100644
--- a/extensions/browser/src/cli/browser-cli-inspect.test.ts
+++ b/extensions/browser/src/cli/browser-cli-inspect.test.ts
@@ -16,10 +16,9 @@ const gatewayMocks = vi.hoisted(() => ({
})),
}));
-vi.mock("openclaw/plugin-sdk/browser-node-runtime", async () => {
- const actual = await vi.importActual(
- "openclaw/plugin-sdk/browser-node-runtime",
- );
+vi.mock("../sdk-node-runtime.js", async () => {
+ const actual =
+ await vi.importActual("../sdk-node-runtime.js");
return {
...actual,
callGatewayFromCli: gatewayMocks.callGatewayFromCli,
diff --git a/extensions/browser/src/cli/command-format.ts b/extensions/browser/src/cli/command-format.ts
index 4cc355beddb..7cac2ed2f9a 100644
--- a/extensions/browser/src/cli/command-format.ts
+++ b/extensions/browser/src/cli/command-format.ts
@@ -1 +1 @@
-export { formatCliCommand } from "openclaw/plugin-sdk/browser-setup-tools";
+export { formatCliCommand } from "../sdk-setup-tools.js";
diff --git a/extensions/browser/src/config/config.ts b/extensions/browser/src/config/config.ts
index 0e1a4df0102..30f8194af71 100644
--- a/extensions/browser/src/config/config.ts
+++ b/extensions/browser/src/config/config.ts
@@ -5,4 +5,4 @@ export {
type BrowserConfig,
type BrowserProfileConfig,
type OpenClawConfig,
-} from "openclaw/plugin-sdk/browser-config-runtime";
+} from "../sdk-config.js";
diff --git a/extensions/browser/src/config/paths.ts b/extensions/browser/src/config/paths.ts
index 085adb06654..e3c16efcc0e 100644
--- a/extensions/browser/src/config/paths.ts
+++ b/extensions/browser/src/config/paths.ts
@@ -1 +1 @@
-export { resolveGatewayPort } from "openclaw/plugin-sdk/browser-config-support";
+export { resolveGatewayPort } from "../sdk-config.js";
diff --git a/extensions/browser/src/config/port-defaults.ts b/extensions/browser/src/config/port-defaults.ts
index f37e01f58bc..eb3d5f3e248 100644
--- a/extensions/browser/src/config/port-defaults.ts
+++ b/extensions/browser/src/config/port-defaults.ts
@@ -2,4 +2,4 @@ export {
DEFAULT_BROWSER_CONTROL_PORT,
deriveDefaultBrowserCdpPortRange,
deriveDefaultBrowserControlPort,
-} from "openclaw/plugin-sdk/browser-config-support";
+} from "../sdk-config.js";
diff --git a/extensions/browser/src/core-api.ts b/extensions/browser/src/core-api.ts
index bda9d6a6d1f..c11c6e6c6c3 100644
--- a/extensions/browser/src/core-api.ts
+++ b/extensions/browser/src/core-api.ts
@@ -83,14 +83,14 @@ export {
selectDefaultNodeFromList,
stringEnum,
theme,
-} from "openclaw/plugin-sdk/browser-setup-tools";
+} from "./sdk-setup-tools.js";
export {
getRuntimeConfig,
normalizePluginsConfig,
parseBooleanValue,
resolveEffectiveEnableState,
shortenHomePath,
-} from "openclaw/plugin-sdk/browser-config-runtime";
+} from "./sdk-config.js";
export {
addGatewayClientOptions,
callGatewayFromCli,
@@ -103,16 +103,13 @@ export {
runCommandWithRuntime,
safeParseJson,
withTimeout,
-} from "openclaw/plugin-sdk/browser-node-runtime";
-export {
- createSubsystemLogger,
- wrapExternalContent,
-} from "openclaw/plugin-sdk/browser-security-runtime";
-export type { AnyAgentTool, NodeListNode } from "openclaw/plugin-sdk/browser-setup-tools";
-export type { OpenClawConfig } from "openclaw/plugin-sdk/browser-config-runtime";
+} from "./sdk-node-runtime.js";
+export { createSubsystemLogger, wrapExternalContent } from "./sdk-security-runtime.js";
+export type { AnyAgentTool, NodeListNode } from "./sdk-setup-tools.js";
+export type { OpenClawConfig } from "./sdk-config.js";
export type {
GatewayRequestHandlers,
GatewayRpcOpts,
NodeSession,
OpenClawPluginService,
-} from "openclaw/plugin-sdk/browser-node-runtime";
+} from "./sdk-node-runtime.js";
diff --git a/extensions/browser/src/doctor-browser.ts b/extensions/browser/src/doctor-browser.ts
index 681ab773560..53f9fbec731 100644
--- a/extensions/browser/src/doctor-browser.ts
+++ b/extensions/browser/src/doctor-browser.ts
@@ -1,4 +1,3 @@
-import { note } from "openclaw/plugin-sdk/browser-setup-tools";
import { normalizeOptionalString } from "openclaw/plugin-sdk/text-runtime";
import {
parseBrowserMajorVersion,
@@ -9,6 +8,7 @@ import {
import { resolveBrowserConfig } from "./browser/config.js";
import type { OpenClawConfig } from "./config/config.js";
import { asRecord } from "./record-shared.js";
+import { note } from "./sdk-setup-tools.js";
const CHROME_MCP_MIN_MAJOR = 144;
const REMOTE_DEBUGGING_PAGES = [
diff --git a/extensions/browser/src/gateway/auth.ts b/extensions/browser/src/gateway/auth.ts
index ecef85414ae..d87bc43638c 100644
--- a/extensions/browser/src/gateway/auth.ts
+++ b/extensions/browser/src/gateway/auth.ts
@@ -1 +1 @@
-export { resolveGatewayAuth } from "openclaw/plugin-sdk/browser-node-runtime";
+export { resolveGatewayAuth } from "../sdk-node-runtime.js";
diff --git a/extensions/browser/src/gateway/browser-request.profile-from-body.test.ts b/extensions/browser/src/gateway/browser-request.profile-from-body.test.ts
index 4a2baa4205f..756b214edad 100644
--- a/extensions/browser/src/gateway/browser-request.profile-from-body.test.ts
+++ b/extensions/browser/src/gateway/browser-request.profile-from-body.test.ts
@@ -18,10 +18,9 @@ vi.mock("openclaw/plugin-sdk/runtime-config-snapshot", async () => {
};
});
-vi.mock("openclaw/plugin-sdk/browser-node-runtime", async () => {
- const actual = await vi.importActual(
- "openclaw/plugin-sdk/browser-node-runtime",
- );
+vi.mock("../sdk-node-runtime.js", async () => {
+ const actual =
+ await vi.importActual("../sdk-node-runtime.js");
return {
...actual,
isNodeCommandAllowed: isNodeCommandAllowedMock,
diff --git a/extensions/browser/src/gateway/net.ts b/extensions/browser/src/gateway/net.ts
index f00fe85275d..0d0b55a016a 100644
--- a/extensions/browser/src/gateway/net.ts
+++ b/extensions/browser/src/gateway/net.ts
@@ -1 +1 @@
-export { isLoopbackHost } from "openclaw/plugin-sdk/browser-config-support";
+export { isLoopbackHost } from "../sdk-node-runtime.js";
diff --git a/extensions/browser/src/gateway/startup-auth.ts b/extensions/browser/src/gateway/startup-auth.ts
index 36989e82dcc..3d6e7f14402 100644
--- a/extensions/browser/src/gateway/startup-auth.ts
+++ b/extensions/browser/src/gateway/startup-auth.ts
@@ -1 +1 @@
-export { ensureGatewayStartupAuth } from "openclaw/plugin-sdk/browser-node-runtime";
+export { ensureGatewayStartupAuth } from "../sdk-node-runtime.js";
diff --git a/extensions/browser/src/infra/errors.ts b/extensions/browser/src/infra/errors.ts
index 0fe8d180abe..49963db651b 100644
--- a/extensions/browser/src/infra/errors.ts
+++ b/extensions/browser/src/infra/errors.ts
@@ -1 +1 @@
-export { extractErrorCode, formatErrorMessage } from "openclaw/plugin-sdk/browser-security-runtime";
+export { extractErrorCode, formatErrorMessage } from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/infra/fs-safe.ts b/extensions/browser/src/infra/fs-safe.ts
index aec2988474c..3e9b84b51f1 100644
--- a/extensions/browser/src/infra/fs-safe.ts
+++ b/extensions/browser/src/infra/fs-safe.ts
@@ -2,4 +2,4 @@ export {
SafeOpenError,
openFileWithinRoot,
writeFileFromPathWithinRoot,
-} from "openclaw/plugin-sdk/browser-security-runtime";
+} from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/infra/net/proxy-env.ts b/extensions/browser/src/infra/net/proxy-env.ts
index e9770a3e2ad..665a73568c9 100644
--- a/extensions/browser/src/infra/net/proxy-env.ts
+++ b/extensions/browser/src/infra/net/proxy-env.ts
@@ -1 +1 @@
-export { hasProxyEnvConfigured } from "openclaw/plugin-sdk/browser-security-runtime";
+export { hasProxyEnvConfigured } from "../../sdk-security-runtime.js";
diff --git a/extensions/browser/src/infra/net/ssrf.ts b/extensions/browser/src/infra/net/ssrf.ts
index a25e674a866..052b16c189a 100644
--- a/extensions/browser/src/infra/net/ssrf.ts
+++ b/extensions/browser/src/infra/net/ssrf.ts
@@ -4,4 +4,4 @@ export {
resolvePinnedHostnameWithPolicy,
type LookupFn,
type SsrFPolicy,
-} from "openclaw/plugin-sdk/browser-security-runtime";
+} from "../../sdk-security-runtime.js";
diff --git a/extensions/browser/src/infra/path-guards.ts b/extensions/browser/src/infra/path-guards.ts
index 834b0992190..1d790b633f8 100644
--- a/extensions/browser/src/infra/path-guards.ts
+++ b/extensions/browser/src/infra/path-guards.ts
@@ -1 +1 @@
-export { isNotFoundPathError, isPathInside } from "openclaw/plugin-sdk/browser-security-runtime";
+export { isNotFoundPathError, isPathInside } from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/infra/ports.ts b/extensions/browser/src/infra/ports.ts
index 3e81fec2a7a..d9d1f156b09 100644
--- a/extensions/browser/src/infra/ports.ts
+++ b/extensions/browser/src/infra/ports.ts
@@ -1 +1 @@
-export { ensurePortAvailable } from "openclaw/plugin-sdk/browser-security-runtime";
+export { ensurePortAvailable } from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/infra/secure-random.ts b/extensions/browser/src/infra/secure-random.ts
index dbe57bc7a3c..e80e94444c7 100644
--- a/extensions/browser/src/infra/secure-random.ts
+++ b/extensions/browser/src/infra/secure-random.ts
@@ -1 +1 @@
-export { generateSecureToken } from "openclaw/plugin-sdk/browser-security-runtime";
+export { generateSecureToken } from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/logging/redact.ts b/extensions/browser/src/logging/redact.ts
index 5cfb75aa946..1bcc89bf3ac 100644
--- a/extensions/browser/src/logging/redact.ts
+++ b/extensions/browser/src/logging/redact.ts
@@ -1 +1 @@
-export { redactSensitiveText } from "openclaw/plugin-sdk/browser-security-runtime";
+export { redactSensitiveText } from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/media/image-ops.ts b/extensions/browser/src/media/image-ops.ts
index 28a63b80842..b8024a6757c 100644
--- a/extensions/browser/src/media/image-ops.ts
+++ b/extensions/browser/src/media/image-ops.ts
@@ -3,4 +3,4 @@ export {
buildImageResizeSideGrid,
getImageMetadata,
resizeToJpeg,
-} from "openclaw/plugin-sdk/browser-setup-tools";
+} from "../sdk-setup-tools.js";
diff --git a/extensions/browser/src/media/store.ts b/extensions/browser/src/media/store.ts
index 2a5ba93d507..405a824a205 100644
--- a/extensions/browser/src/media/store.ts
+++ b/extensions/browser/src/media/store.ts
@@ -1 +1 @@
-export { ensureMediaDir, saveMediaBuffer } from "openclaw/plugin-sdk/browser-setup-tools";
+export { ensureMediaDir, saveMediaBuffer } from "../sdk-setup-tools.js";
diff --git a/extensions/browser/src/node-host/invoke-browser.test.ts b/extensions/browser/src/node-host/invoke-browser.test.ts
index 193f5cf28d9..620e3f389f4 100644
--- a/extensions/browser/src/node-host/invoke-browser.test.ts
+++ b/extensions/browser/src/node-host/invoke-browser.test.ts
@@ -26,12 +26,12 @@ const browserConfigMocks = vi.hoisted(() => ({
})),
}));
-vi.mock("openclaw/plugin-sdk/browser-config-runtime", () => ({
+vi.mock("../sdk-config.js", () => ({
getRuntimeConfig: configMocks.loadConfig,
loadConfig: configMocks.loadConfig,
}));
-vi.mock("openclaw/plugin-sdk/browser-node-runtime", () => ({
+vi.mock("../sdk-node-runtime.js", () => ({
withTimeout: vi.fn(
async (
run: (signal: AbortSignal | undefined) => Promise,
@@ -66,7 +66,7 @@ vi.mock("openclaw/plugin-sdk/browser-node-runtime", () => ({
),
}));
-vi.mock("openclaw/plugin-sdk/browser-setup-tools", () => ({
+vi.mock("../sdk-setup-tools.js", () => ({
detectMime: vi.fn(async () => "image/png"),
}));
diff --git a/extensions/browser/src/node-host/invoke-browser.ts b/extensions/browser/src/node-host/invoke-browser.ts
index 4c7edafe9a5..5b655bf958c 100644
--- a/extensions/browser/src/node-host/invoke-browser.ts
+++ b/extensions/browser/src/node-host/invoke-browser.ts
@@ -1,7 +1,4 @@
import fsPromises from "node:fs/promises";
-import { getRuntimeConfig } from "openclaw/plugin-sdk/browser-config-runtime";
-import { withTimeout } from "openclaw/plugin-sdk/browser-node-runtime";
-import { detectMime } from "openclaw/plugin-sdk/browser-setup-tools";
import { redactCdpUrl } from "../browser/cdp.helpers.js";
import { resolveBrowserConfig } from "../browser/config.js";
import {
@@ -14,6 +11,9 @@ import {
createBrowserControlContext,
startBrowserControlServiceFromConfig,
} from "../control-service.js";
+import { getRuntimeConfig } from "../sdk-config.js";
+import { withTimeout } from "../sdk-node-runtime.js";
+import { detectMime } from "../sdk-setup-tools.js";
type BrowserProxyParams = {
method?: string;
diff --git a/extensions/browser/src/plugin-enabled.ts b/extensions/browser/src/plugin-enabled.ts
index 2ab2d09c9e2..8d26e873139 100644
--- a/extensions/browser/src/plugin-enabled.ts
+++ b/extensions/browser/src/plugin-enabled.ts
@@ -1,8 +1,5 @@
-import type { OpenClawConfig } from "openclaw/plugin-sdk/browser-config-runtime";
-import {
- normalizePluginsConfig,
- resolveEffectiveEnableState,
-} from "openclaw/plugin-sdk/browser-config-runtime";
+import type { OpenClawConfig } from "./sdk-config.js";
+import { normalizePluginsConfig, resolveEffectiveEnableState } from "./sdk-config.js";
export function isDefaultBrowserPluginEnabled(cfg: OpenClawConfig): boolean {
return resolveEffectiveEnableState({
diff --git a/extensions/browser/src/plugin-service.test.ts b/extensions/browser/src/plugin-service.test.ts
index b6d150a0af3..e8e4c7aec5b 100644
--- a/extensions/browser/src/plugin-service.test.ts
+++ b/extensions/browser/src/plugin-service.test.ts
@@ -20,7 +20,7 @@ const runtimeMocks = vi.hoisted(() => ({
startLazyPluginServiceModule: vi.fn(async (_params: StartLazyPluginServiceModuleParams) => null),
}));
-vi.mock("openclaw/plugin-sdk/browser-node-runtime", () => ({
+vi.mock("./sdk-node-runtime.js", () => ({
startLazyPluginServiceModule: runtimeMocks.startLazyPluginServiceModule,
}));
diff --git a/extensions/browser/src/plugin-service.ts b/extensions/browser/src/plugin-service.ts
index b68cc3334f5..47a361d858c 100644
--- a/extensions/browser/src/plugin-service.ts
+++ b/extensions/browser/src/plugin-service.ts
@@ -2,7 +2,7 @@ import {
startLazyPluginServiceModule,
type LazyPluginServiceHandle,
type OpenClawPluginService,
-} from "openclaw/plugin-sdk/browser-node-runtime";
+} from "./sdk-node-runtime.js";
type BrowserControlHandle = LazyPluginServiceHandle | null;
const UNSAFE_BROWSER_CONTROL_OVERRIDE_SPECIFIER = /^(?:data|http|https|node):/i;
diff --git a/extensions/browser/src/process/exec.ts b/extensions/browser/src/process/exec.ts
index 8cef8f8fc7c..e0f23baa49f 100644
--- a/extensions/browser/src/process/exec.ts
+++ b/extensions/browser/src/process/exec.ts
@@ -1 +1 @@
-export { runExec } from "openclaw/plugin-sdk/browser-node-runtime";
+export { runExec } from "../sdk-node-runtime.js";
diff --git a/extensions/browser/src/sdk-config.ts b/extensions/browser/src/sdk-config.ts
new file mode 100644
index 00000000000..0123fb597d2
--- /dev/null
+++ b/extensions/browser/src/sdk-config.ts
@@ -0,0 +1,98 @@
+import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime";
+
+export {
+ getRuntimeConfig,
+ getRuntimeConfigSnapshot,
+ replaceConfigFile,
+} from "openclaw/plugin-sdk/config-runtime";
+export type {
+ BrowserConfig,
+ BrowserProfileConfig,
+ OpenClawConfig,
+} from "openclaw/plugin-sdk/config-types";
+export {
+ normalizePluginsConfig,
+ resolveEffectiveEnableState,
+} from "openclaw/plugin-sdk/plugin-config-runtime";
+export { resolveGatewayPort } from "openclaw/plugin-sdk/core";
+export {
+ CONFIG_DIR,
+ escapeRegExp,
+ resolveUserPath,
+ shortenHomePath,
+} from "openclaw/plugin-sdk/text-runtime";
+export { normalizeOptionalLowercaseString };
+
+export type PortRange = { start: number; end: number };
+
+const DEFAULT_BROWSER_CDP_PORT_RANGE_START = 18800;
+const DEFAULT_BROWSER_CDP_PORT_RANGE_END = 18899;
+const DEFAULT_BROWSER_CDP_PORT_RANGE_SPAN =
+ DEFAULT_BROWSER_CDP_PORT_RANGE_END - DEFAULT_BROWSER_CDP_PORT_RANGE_START;
+
+export const DEFAULT_BROWSER_CONTROL_PORT = 18791;
+
+function isValidPort(port: number): boolean {
+ return Number.isFinite(port) && port > 0 && port <= 65535;
+}
+
+function clampPort(port: number, fallback: number): number {
+ return isValidPort(port) ? port : fallback;
+}
+
+function derivePort(base: number, offset: number, fallback: number): number {
+ return clampPort(base + offset, fallback);
+}
+
+export function deriveDefaultBrowserControlPort(gatewayPort: number): number {
+ return derivePort(gatewayPort, 2, DEFAULT_BROWSER_CONTROL_PORT);
+}
+
+export function deriveDefaultBrowserCdpPortRange(browserControlPort: number): PortRange {
+ const start = derivePort(browserControlPort, 9, DEFAULT_BROWSER_CDP_PORT_RANGE_START);
+ const end = start + DEFAULT_BROWSER_CDP_PORT_RANGE_SPAN;
+ if (end <= 65535) {
+ return { start, end };
+ }
+ return {
+ start: DEFAULT_BROWSER_CDP_PORT_RANGE_START,
+ end: DEFAULT_BROWSER_CDP_PORT_RANGE_END,
+ };
+}
+
+export type BooleanParseOptions = {
+ truthy?: string[];
+ falsy?: string[];
+};
+
+const DEFAULT_TRUTHY = ["true", "1", "yes", "on"] as const;
+const DEFAULT_FALSY = ["false", "0", "no", "off"] as const;
+const DEFAULT_TRUTHY_SET = new Set(DEFAULT_TRUTHY);
+const DEFAULT_FALSY_SET = new Set(DEFAULT_FALSY);
+
+export function parseBooleanValue(
+ value: unknown,
+ options: BooleanParseOptions = {},
+): boolean | undefined {
+ if (typeof value === "boolean") {
+ return value;
+ }
+ if (typeof value !== "string") {
+ return undefined;
+ }
+ const normalized = normalizeOptionalLowercaseString(value);
+ if (!normalized) {
+ return undefined;
+ }
+ const truthy = options.truthy ?? DEFAULT_TRUTHY;
+ const falsy = options.falsy ?? DEFAULT_FALSY;
+ const truthySet = truthy === DEFAULT_TRUTHY ? DEFAULT_TRUTHY_SET : new Set(truthy);
+ const falsySet = falsy === DEFAULT_FALSY ? DEFAULT_FALSY_SET : new Set(falsy);
+ if (truthySet.has(normalized)) {
+ return true;
+ }
+ if (falsySet.has(normalized)) {
+ return false;
+ }
+ return undefined;
+}
diff --git a/extensions/browser/src/sdk-node-runtime.ts b/extensions/browser/src/sdk-node-runtime.ts
new file mode 100644
index 00000000000..34e20591896
--- /dev/null
+++ b/extensions/browser/src/sdk-node-runtime.ts
@@ -0,0 +1,63 @@
+export {
+ addGatewayClientOptions,
+ callGatewayFromCli,
+ ensureGatewayStartupAuth,
+ ErrorCodes,
+ errorShape,
+ isLoopbackHost,
+ isNodeCommandAllowed,
+ rawDataToString,
+ respondUnavailableOnNodeInvokeError,
+ resolveGatewayAuth,
+ resolveNodeCommandAllowlist,
+ safeParseJson,
+} from "openclaw/plugin-sdk/gateway-runtime";
+export type {
+ GatewayRequestHandlers,
+ GatewayRpcOpts,
+ NodeSession,
+} from "openclaw/plugin-sdk/gateway-runtime";
+export { runExec } from "openclaw/plugin-sdk/process-runtime";
+export { runCommandWithRuntime } from "openclaw/plugin-sdk/cli-runtime";
+export type { OpenClawPluginService } from "openclaw/plugin-sdk/plugin-entry";
+export {
+ startLazyPluginServiceModule,
+ type LazyPluginServiceHandle,
+} from "openclaw/plugin-sdk/plugin-runtime";
+export { defaultRuntime } from "openclaw/plugin-sdk/runtime-env";
+
+export async function withTimeout(
+ work: (signal: AbortSignal | undefined) => Promise,
+ timeoutMs?: number,
+ label?: string,
+): Promise {
+ const resolved =
+ typeof timeoutMs === "number" && Number.isFinite(timeoutMs)
+ ? Math.max(1, Math.floor(timeoutMs))
+ : undefined;
+ if (!resolved) {
+ return await work(undefined);
+ }
+
+ const abortCtrl = new AbortController();
+ const timeoutError = new Error(`${label ?? "request"} timed out`);
+ const timer = setTimeout(() => abortCtrl.abort(timeoutError), resolved);
+ timer.unref?.();
+
+ let abortListener: (() => void) | undefined;
+ const abortPromise: Promise = abortCtrl.signal.aborted
+ ? Promise.reject(abortCtrl.signal.reason ?? timeoutError)
+ : new Promise((_, reject) => {
+ abortListener = () => reject(abortCtrl.signal.reason ?? timeoutError);
+ abortCtrl.signal.addEventListener("abort", abortListener, { once: true });
+ });
+
+ try {
+ return await Promise.race([work(abortCtrl.signal), abortPromise]);
+ } finally {
+ clearTimeout(timer);
+ if (abortListener) {
+ abortCtrl.signal.removeEventListener("abort", abortListener);
+ }
+ }
+}
diff --git a/extensions/browser/src/sdk-security-runtime.ts b/extensions/browser/src/sdk-security-runtime.ts
new file mode 100644
index 00000000000..56de1ea7b51
--- /dev/null
+++ b/extensions/browser/src/sdk-security-runtime.ts
@@ -0,0 +1,24 @@
+export { createSubsystemLogger } from "openclaw/plugin-sdk/logging-core";
+export {
+ ensurePortAvailable,
+ extractErrorCode,
+ formatErrorMessage,
+ generateSecureToken,
+ hasProxyEnvConfigured,
+ isBlockedHostnameOrIp,
+ isNotFoundPathError,
+ isPathInside,
+ isPrivateNetworkAllowedByPolicy,
+ matchesHostnameAllowlist,
+ normalizeHostname,
+ openFileWithinRoot,
+ redactSensitiveText,
+ resolvePinnedHostnameWithPolicy,
+ resolvePreferredOpenClawTmpDir,
+ safeEqualSecret,
+ SafeOpenError,
+ SsrFBlockedError,
+ wrapExternalContent,
+ writeFileFromPathWithinRoot,
+} from "openclaw/plugin-sdk/security-runtime";
+export type { LookupFn, SsrFPolicy } from "openclaw/plugin-sdk/security-runtime";
diff --git a/extensions/browser/src/sdk-setup-tools.ts b/extensions/browser/src/sdk-setup-tools.ts
new file mode 100644
index 00000000000..03fc423c38b
--- /dev/null
+++ b/extensions/browser/src/sdk-setup-tools.ts
@@ -0,0 +1,30 @@
+export {
+ callGatewayTool,
+ listNodes,
+ resolveNodeIdFromList,
+ selectDefaultNodeFromList,
+} from "openclaw/plugin-sdk/agent-harness-runtime";
+export type { AnyAgentTool, NodeListNode } from "openclaw/plugin-sdk/agent-harness-runtime";
+export {
+ imageResultFromFile,
+ jsonResult,
+ readStringParam,
+} from "openclaw/plugin-sdk/channel-actions";
+export { optionalStringEnum, stringEnum } from "openclaw/plugin-sdk/channel-actions";
+export {
+ formatCliCommand,
+ formatHelpExamples,
+ inheritOptionFromParent,
+ note,
+ theme,
+} from "openclaw/plugin-sdk/cli-runtime";
+export { danger, info } from "openclaw/plugin-sdk/runtime-env";
+export {
+ IMAGE_REDUCE_QUALITY_STEPS,
+ buildImageResizeSideGrid,
+ getImageMetadata,
+ resizeToJpeg,
+} from "openclaw/plugin-sdk/media-runtime";
+export { detectMime } from "openclaw/plugin-sdk/media-mime";
+export { ensureMediaDir, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
+export { formatDocsLink } from "openclaw/plugin-sdk/setup-tools";
diff --git a/extensions/browser/src/security/secret-equal.ts b/extensions/browser/src/security/secret-equal.ts
index b885781aa02..61cd4da2ea8 100644
--- a/extensions/browser/src/security/secret-equal.ts
+++ b/extensions/browser/src/security/secret-equal.ts
@@ -1 +1 @@
-export { safeEqualSecret } from "openclaw/plugin-sdk/browser-security-runtime";
+export { safeEqualSecret } from "../sdk-security-runtime.js";
diff --git a/extensions/browser/src/test-utils/vitest-mock-fn.ts b/extensions/browser/src/test-utils/vitest-mock-fn.ts
index 36d5e481eb5..eab9c6ec04d 100644
--- a/extensions/browser/src/test-utils/vitest-mock-fn.ts
+++ b/extensions/browser/src/test-utils/vitest-mock-fn.ts
@@ -1 +1,3 @@
-export type { MockFn } from "openclaw/plugin-sdk/browser-setup-tools";
+// oxlint-disable-next-line typescript/no-explicit-any
+export type MockFn any = (...args: any[]) => any> =
+ import("vitest").Mock;
diff --git a/extensions/browser/src/utils.ts b/extensions/browser/src/utils.ts
index ef7f7958d72..10786b9270c 100644
--- a/extensions/browser/src/utils.ts
+++ b/extensions/browser/src/utils.ts
@@ -1,6 +1 @@
-export {
- CONFIG_DIR,
- escapeRegExp,
- resolveUserPath,
- shortenHomePath,
-} from "openclaw/plugin-sdk/browser-config-support";
+export { CONFIG_DIR, escapeRegExp, resolveUserPath, shortenHomePath } from "./sdk-config.js";
diff --git a/extensions/browser/src/utils/boolean.ts b/extensions/browser/src/utils/boolean.ts
index bef72de2b4d..6ae213c2a67 100644
--- a/extensions/browser/src/utils/boolean.ts
+++ b/extensions/browser/src/utils/boolean.ts
@@ -1 +1 @@
-export { parseBooleanValue } from "openclaw/plugin-sdk/browser-config-runtime";
+export { parseBooleanValue } from "../sdk-config.js";
diff --git a/extensions/browser/test-support/browser-security.mock.ts b/extensions/browser/test-support/browser-security.mock.ts
new file mode 100644
index 00000000000..7f0bd6e20d1
--- /dev/null
+++ b/extensions/browser/test-support/browser-security.mock.ts
@@ -0,0 +1,16 @@
+import { vi } from "vitest";
+
+vi.mock("../src/sdk-security-runtime.js", async () => {
+ const actual = await vi.importActual(
+ "../src/sdk-security-runtime.js",
+ );
+ const lookupFn = async (_hostname: string, options?: { all?: boolean }) => {
+ const result = { address: "93.184.216.34", family: 4 };
+ return options?.all === true ? [result] : result;
+ };
+ return {
+ ...actual,
+ resolvePinnedHostnameWithPolicy: (hostname: string, params: object = {}) =>
+ actual.resolvePinnedHostnameWithPolicy(hostname, { ...params, lookupFn: lookupFn as never }),
+ };
+});
diff --git a/extensions/github-copilot/embeddings.test.ts b/extensions/github-copilot/embeddings.test.ts
index df6564574a5..dfe104fa5dc 100644
--- a/extensions/github-copilot/embeddings.test.ts
+++ b/extensions/github-copilot/embeddings.test.ts
@@ -13,7 +13,7 @@ vi.mock("openclaw/plugin-sdk/secret-input-runtime", () => ({
resolveConfiguredSecretInputString: resolveConfiguredSecretInputStringMock,
}));
-vi.mock("openclaw/plugin-sdk/github-copilot-token", () => ({
+vi.mock("./token.js", () => ({
DEFAULT_COPILOT_API_BASE_URL: "https://api.githubcopilot.test",
resolveCopilotApiToken: resolveCopilotApiTokenMock,
}));
diff --git a/extensions/github-copilot/embeddings.ts b/extensions/github-copilot/embeddings.ts
index 6283764233c..0bd1401c4b1 100644
--- a/extensions/github-copilot/embeddings.ts
+++ b/extensions/github-copilot/embeddings.ts
@@ -1,7 +1,3 @@
-import {
- DEFAULT_COPILOT_API_BASE_URL,
- resolveCopilotApiToken,
-} from "openclaw/plugin-sdk/github-copilot-token";
import {
buildRemoteBaseUrlPolicy,
sanitizeAndNormalizeEmbedding,
@@ -12,6 +8,7 @@ import {
import { resolveConfiguredSecretInputString } from "openclaw/plugin-sdk/secret-input-runtime";
import { fetchWithSsrFGuard, type SsrFPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
import { resolveFirstGithubToken } from "./auth.js";
+import { DEFAULT_COPILOT_API_BASE_URL, resolveCopilotApiToken } from "./token.js";
const COPILOT_EMBEDDING_PROVIDER_ID = "github-copilot";
diff --git a/extensions/github-copilot/token.ts b/extensions/github-copilot/token.ts
index b2d8625f184..16715538a1c 100644
--- a/extensions/github-copilot/token.ts
+++ b/extensions/github-copilot/token.ts
@@ -1,7 +1,169 @@
-import {
- DEFAULT_COPILOT_API_BASE_URL,
- deriveCopilotApiBaseUrlFromToken,
- resolveCopilotApiToken,
-} from "openclaw/plugin-sdk/github-copilot-token";
+import path from "node:path";
+import { loadJsonFile, saveJsonFile } from "openclaw/plugin-sdk/json-store";
+import { resolveProviderEndpoint } from "openclaw/plugin-sdk/provider-model-shared";
+import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
+import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
-export { DEFAULT_COPILOT_API_BASE_URL, deriveCopilotApiBaseUrlFromToken, resolveCopilotApiToken };
+const COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
+const COPILOT_EDITOR_VERSION = "vscode/1.96.2";
+const COPILOT_USER_AGENT = "GitHubCopilotChat/0.26.7";
+const COPILOT_EDITOR_PLUGIN_VERSION = "copilot-chat/0.35.0";
+const COPILOT_GITHUB_API_VERSION = "2025-04-01";
+
+export const DEFAULT_COPILOT_API_BASE_URL = "https://api.individual.githubcopilot.com";
+
+export type CachedCopilotToken = {
+ token: string;
+ expiresAt: number;
+ updatedAt: number;
+};
+
+function buildCopilotIdeHeaders(
+ params: {
+ includeApiVersion?: boolean;
+ } = {},
+): Record {
+ return {
+ "Editor-Version": COPILOT_EDITOR_VERSION,
+ "Editor-Plugin-Version": COPILOT_EDITOR_PLUGIN_VERSION,
+ "User-Agent": COPILOT_USER_AGENT,
+ ...(params.includeApiVersion ? { "X-Github-Api-Version": COPILOT_GITHUB_API_VERSION } : {}),
+ };
+}
+
+function resolveCopilotTokenCachePath(env: NodeJS.ProcessEnv = process.env) {
+ return path.join(resolveStateDir(env), "credentials", "github-copilot.token.json");
+}
+
+function isTokenUsable(cache: CachedCopilotToken, now = Date.now()): boolean {
+ return cache.expiresAt - now > 5 * 60 * 1000;
+}
+
+function parseCopilotTokenResponse(value: unknown): {
+ token: string;
+ expiresAt: number;
+} {
+ if (!value || typeof value !== "object") {
+ throw new Error("Unexpected response from GitHub Copilot token endpoint");
+ }
+ const asRecord = value as Record;
+ const token = asRecord.token;
+ const expiresAt = asRecord.expires_at;
+ if (typeof token !== "string" || token.trim().length === 0) {
+ throw new Error("Copilot token response missing token");
+ }
+
+ let expiresAtMs: number;
+ if (typeof expiresAt === "number" && Number.isFinite(expiresAt)) {
+ expiresAtMs = expiresAt < 100_000_000_000 ? expiresAt * 1000 : expiresAt;
+ } else if (typeof expiresAt === "string" && expiresAt.trim().length > 0) {
+ const parsed = Number.parseInt(expiresAt, 10);
+ if (!Number.isFinite(parsed)) {
+ throw new Error("Copilot token response has invalid expires_at");
+ }
+ expiresAtMs = parsed < 100_000_000_000 ? parsed * 1000 : parsed;
+ } else {
+ throw new Error("Copilot token response missing expires_at");
+ }
+
+ return { token, expiresAt: expiresAtMs };
+}
+
+function resolveCopilotProxyHost(proxyEp: string): string | null {
+ const trimmed = proxyEp.trim();
+ if (!trimmed) {
+ return null;
+ }
+
+ const urlText = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
+ try {
+ const url = new URL(urlText);
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
+ return null;
+ }
+ return normalizeLowercaseStringOrEmpty(url.hostname);
+ } catch {
+ return null;
+ }
+}
+
+export function deriveCopilotApiBaseUrlFromToken(token: string): string | null {
+ const trimmed = token.trim();
+ if (!trimmed) {
+ return null;
+ }
+
+ const match = trimmed.match(/(?:^|;)\s*proxy-ep=([^;\s]+)/i);
+ const proxyEp = match?.[1]?.trim();
+ if (!proxyEp) {
+ return null;
+ }
+
+ const proxyHost = resolveCopilotProxyHost(proxyEp);
+ if (!proxyHost) {
+ return null;
+ }
+ const host = proxyHost.replace(/^proxy\./i, "api.");
+
+ const baseUrl = `https://${host}`;
+ return resolveProviderEndpoint(baseUrl).endpointClass === "invalid" ? null : baseUrl;
+}
+
+export async function resolveCopilotApiToken(params: {
+ githubToken: string;
+ env?: NodeJS.ProcessEnv;
+ fetchImpl?: typeof fetch;
+ cachePath?: string;
+ loadJsonFileImpl?: (path: string) => unknown;
+ saveJsonFileImpl?: (path: string, value: CachedCopilotToken) => void;
+}): Promise<{
+ token: string;
+ expiresAt: number;
+ source: string;
+ baseUrl: string;
+}> {
+ const env = params.env ?? process.env;
+ const cachePath = params.cachePath?.trim() || resolveCopilotTokenCachePath(env);
+ const loadJsonFileFn = params.loadJsonFileImpl ?? loadJsonFile;
+ const saveJsonFileFn = params.saveJsonFileImpl ?? saveJsonFile;
+ const cached = loadJsonFileFn(cachePath) as CachedCopilotToken | undefined;
+ if (cached && typeof cached.token === "string" && typeof cached.expiresAt === "number") {
+ if (isTokenUsable(cached)) {
+ return {
+ token: cached.token,
+ expiresAt: cached.expiresAt,
+ source: `cache:${cachePath}`,
+ baseUrl: deriveCopilotApiBaseUrlFromToken(cached.token) ?? DEFAULT_COPILOT_API_BASE_URL,
+ };
+ }
+ }
+
+ const fetchImpl = params.fetchImpl ?? fetch;
+ const res = await fetchImpl(COPILOT_TOKEN_URL, {
+ method: "GET",
+ headers: {
+ Accept: "application/json",
+ Authorization: `Bearer ${params.githubToken}`,
+ ...buildCopilotIdeHeaders({ includeApiVersion: true }),
+ },
+ });
+
+ if (!res.ok) {
+ throw new Error(`Copilot token exchange failed: HTTP ${res.status}`);
+ }
+
+ const json = parseCopilotTokenResponse(await res.json());
+ const payload: CachedCopilotToken = {
+ token: json.token,
+ expiresAt: json.expiresAt,
+ updatedAt: Date.now(),
+ };
+ saveJsonFileFn(cachePath, payload);
+
+ return {
+ token: payload.token,
+ expiresAt: payload.expiresAt,
+ source: `fetched:${COPILOT_TOKEN_URL}`,
+ baseUrl: deriveCopilotApiBaseUrlFromToken(payload.token) ?? DEFAULT_COPILOT_API_BASE_URL,
+ };
+}
diff --git a/extensions/matrix/src/runtime-api.ts b/extensions/matrix/src/runtime-api.ts
index 7b534880674..eeabd6fab76 100644
--- a/extensions/matrix/src/runtime-api.ts
+++ b/extensions/matrix/src/runtime-api.ts
@@ -107,7 +107,7 @@ export {
formatZonedTimestamp,
type PluginRuntime,
type RuntimeLogger,
-} from "openclaw/plugin-sdk/matrix-runtime-shared";
+} from "openclaw/plugin-sdk/core";
export type { ReplyPayload } from "openclaw/plugin-sdk/reply-runtime";
// resolveMatrixAccountStringValues already comes from the Matrix API barrel.
// Re-exporting auth-precedence here makes Jiti try to define the same export twice.
diff --git a/extensions/memory-core/index.test.ts b/extensions/memory-core/index.test.ts
index b12877352b8..867481d24c0 100644
--- a/extensions/memory-core/index.test.ts
+++ b/extensions/memory-core/index.test.ts
@@ -1,4 +1,4 @@
-import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core";
+import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import { describe, expect, it } from "vitest";
import {
buildMemoryFlushPlan,
diff --git a/extensions/memory-core/src/dreaming-command.test.ts b/extensions/memory-core/src/dreaming-command.test.ts
index 872fd312788..4ad14cb9742 100644
--- a/extensions/memory-core/src/dreaming-command.test.ts
+++ b/extensions/memory-core/src/dreaming-command.test.ts
@@ -1,8 +1,9 @@
+import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import type {
OpenClawPluginCommandDefinition,
PluginCommandContext,
} from "openclaw/plugin-sdk/core";
-import type { OpenClawConfig, OpenClawPluginApi } from "openclaw/plugin-sdk/memory-core";
+import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
import { describe, expect, it, vi } from "vitest";
import { registerDreamingCommand } from "./dreaming-command.js";
diff --git a/extensions/memory-core/src/dreaming-phases.test.ts b/extensions/memory-core/src/dreaming-phases.test.ts
index 72c79b382a2..c7d9d382d24 100644
--- a/extensions/memory-core/src/dreaming-phases.test.ts
+++ b/extensions/memory-core/src/dreaming-phases.test.ts
@@ -1,9 +1,9 @@
import { createHash } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
+import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import { RequestScopedSubagentRuntimeError } from "openclaw/plugin-sdk/error-runtime";
-import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core";
-import { resolveSessionTranscriptsDirForAgent } from "openclaw/plugin-sdk/memory-core";
+import { resolveSessionTranscriptsDirForAgent } from "openclaw/plugin-sdk/memory-core-host-runtime-core";
import {
resolveMemoryCorePluginConfig,
resolveMemoryLightDreamingConfig,
diff --git a/extensions/memory-core/src/dreaming.test.ts b/extensions/memory-core/src/dreaming.test.ts
index 6a05ea77c3f..d381e8722ef 100644
--- a/extensions/memory-core/src/dreaming.test.ts
+++ b/extensions/memory-core/src/dreaming.test.ts
@@ -1,6 +1,6 @@
import fs from "node:fs/promises";
import path from "node:path";
-import type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core";
+import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
import {
enqueueSystemEvent,
resetSystemEventsForTest,
diff --git a/extensions/memory-core/src/memory/index.test.ts b/extensions/memory-core/src/memory/index.test.ts
index 3db96d20d93..9f280c92c9a 100644
--- a/extensions/memory-core/src/memory/index.test.ts
+++ b/extensions/memory-core/src/memory/index.test.ts
@@ -2,12 +2,12 @@ import { mkdirSync, rmSync } from "node:fs";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
-import { resolveSessionTranscriptsDirForAgent } from "openclaw/plugin-sdk/memory-core";
import {
clearMemoryEmbeddingProviders as clearRegistry,
listRegisteredMemoryEmbeddingProviderAdapters as listRegisteredAdapters,
registerMemoryEmbeddingProvider as registerAdapter,
} from "openclaw/plugin-sdk/memory-core-host-engine-embeddings";
+import { resolveSessionTranscriptsDirForAgent } from "openclaw/plugin-sdk/memory-core-host-runtime-core";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import "./test-runtime-mocks.js";
import type { MemoryIndexManager } from "./index.js";
diff --git a/extensions/tsconfig.package-boundary.paths.json b/extensions/tsconfig.package-boundary.paths.json
index c439cb65c5d..c0448ba22ef 100644
--- a/extensions/tsconfig.package-boundary.paths.json
+++ b/extensions/tsconfig.package-boundary.paths.json
@@ -12,18 +12,6 @@
"openclaw/plugin-sdk/browser-maintenance": [
"../packages/plugin-sdk/dist/extensions/browser/browser-maintenance.d.ts"
],
- "openclaw/plugin-sdk/browser-config-runtime": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-config-runtime.d.ts"
- ],
- "openclaw/plugin-sdk/browser-node-runtime": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-node-runtime.d.ts"
- ],
- "openclaw/plugin-sdk/browser-setup-tools": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-setup-tools.d.ts"
- ],
- "openclaw/plugin-sdk/browser-security-runtime": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-security-runtime.d.ts"
- ],
"openclaw/plugin-sdk/channel-secret-basic-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-secret-basic-runtime.d.ts"
],
diff --git a/extensions/xai/tsconfig.json b/extensions/xai/tsconfig.json
index 319004f3bc9..dd1837a92d4 100644
--- a/extensions/xai/tsconfig.json
+++ b/extensions/xai/tsconfig.json
@@ -13,18 +13,6 @@
"openclaw/plugin-sdk/browser-maintenance": [
"../../dist/plugin-sdk/src/plugin-sdk/browser-maintenance.d.ts"
],
- "openclaw/plugin-sdk/browser-config-runtime": [
- "../../dist/plugin-sdk/src/plugin-sdk/browser-config-runtime.d.ts"
- ],
- "openclaw/plugin-sdk/browser-node-runtime": [
- "../../dist/plugin-sdk/src/plugin-sdk/browser-node-runtime.d.ts"
- ],
- "openclaw/plugin-sdk/browser-setup-tools": [
- "../../dist/plugin-sdk/src/plugin-sdk/browser-setup-tools.d.ts"
- ],
- "openclaw/plugin-sdk/browser-security-runtime": [
- "../../dist/plugin-sdk/src/plugin-sdk/browser-security-runtime.d.ts"
- ],
"openclaw/plugin-sdk/channel-secret-runtime": [
"../../dist/plugin-sdk/src/plugin-sdk/channel-secret-runtime.d.ts"
],
diff --git a/package.json b/package.json
index 01e25a5e0e4..9fea64b7924 100644
--- a/package.json
+++ b/package.json
@@ -370,10 +370,6 @@
"types": "./dist/plugin-sdk/conversation-runtime.d.ts",
"default": "./dist/plugin-sdk/conversation-runtime.js"
},
- "./plugin-sdk/matrix-runtime-shared": {
- "types": "./dist/plugin-sdk/matrix-runtime-shared.d.ts",
- "default": "./dist/plugin-sdk/matrix-runtime-shared.js"
- },
"./plugin-sdk/thread-bindings-runtime": {
"types": "./dist/plugin-sdk/thread-bindings-runtime.d.ts",
"default": "./dist/plugin-sdk/thread-bindings-runtime.js"
@@ -442,10 +438,6 @@
"types": "./dist/plugin-sdk/gateway-runtime.d.ts",
"default": "./dist/plugin-sdk/gateway-runtime.js"
},
- "./plugin-sdk/github-copilot-token": {
- "types": "./dist/plugin-sdk/github-copilot-token.d.ts",
- "default": "./dist/plugin-sdk/github-copilot-token.js"
- },
"./plugin-sdk/cli-runtime": {
"types": "./dist/plugin-sdk/cli-runtime.d.ts",
"default": "./dist/plugin-sdk/cli-runtime.js"
@@ -598,26 +590,6 @@
"types": "./dist/plugin-sdk/browser-config.d.ts",
"default": "./dist/plugin-sdk/browser-config.js"
},
- "./plugin-sdk/browser-config-runtime": {
- "types": "./dist/plugin-sdk/browser-config-runtime.d.ts",
- "default": "./dist/plugin-sdk/browser-config-runtime.js"
- },
- "./plugin-sdk/browser-config-support": {
- "types": "./dist/plugin-sdk/browser-config-support.d.ts",
- "default": "./dist/plugin-sdk/browser-config-support.js"
- },
- "./plugin-sdk/browser-node-runtime": {
- "types": "./dist/plugin-sdk/browser-node-runtime.d.ts",
- "default": "./dist/plugin-sdk/browser-node-runtime.js"
- },
- "./plugin-sdk/browser-security-runtime": {
- "types": "./dist/plugin-sdk/browser-security-runtime.d.ts",
- "default": "./dist/plugin-sdk/browser-security-runtime.js"
- },
- "./plugin-sdk/browser-setup-tools": {
- "types": "./dist/plugin-sdk/browser-setup-tools.d.ts",
- "default": "./dist/plugin-sdk/browser-setup-tools.js"
- },
"./plugin-sdk/boolean-param": {
"types": "./dist/plugin-sdk/boolean-param.d.ts",
"default": "./dist/plugin-sdk/boolean-param.js"
@@ -954,10 +926,6 @@
"types": "./dist/plugin-sdk/qa-runner-runtime.d.ts",
"default": "./dist/plugin-sdk/qa-runner-runtime.js"
},
- "./plugin-sdk/memory-core": {
- "types": "./dist/plugin-sdk/memory-core.d.ts",
- "default": "./dist/plugin-sdk/memory-core.js"
- },
"./plugin-sdk/memory-core-engine-runtime": {
"types": "./dist/plugin-sdk/memory-core-engine-runtime.d.ts",
"default": "./dist/plugin-sdk/memory-core-engine-runtime.js"
diff --git a/packages/plugin-sdk/package.json b/packages/plugin-sdk/package.json
index 2c82f027859..1fe473bf70a 100644
--- a/packages/plugin-sdk/package.json
+++ b/packages/plugin-sdk/package.json
@@ -56,18 +56,10 @@
"types": "./dist/src/plugin-sdk/transport-ready-runtime.d.ts",
"default": "./src/transport-ready-runtime.ts"
},
- "./browser-config-runtime": {
- "types": "./dist/src/plugin-sdk/browser-config-runtime.d.ts",
- "default": "./src/browser-config-runtime.ts"
- },
"./core": {
"types": "./dist/src/plugin-sdk/core.d.ts",
"default": "./src/core.ts"
},
- "./browser-node-runtime": {
- "types": "./dist/src/plugin-sdk/browser-node-runtime.d.ts",
- "default": "./src/browser-node-runtime.ts"
- },
"./config-runtime": {
"types": "./dist/src/plugin-sdk/config-runtime.d.ts",
"default": "./src/config-runtime.ts"
@@ -88,14 +80,6 @@
"types": "./dist/src/plugin-sdk/cron-store-runtime.d.ts",
"default": "./src/cron-store-runtime.ts"
},
- "./browser-setup-tools": {
- "types": "./dist/src/plugin-sdk/browser-setup-tools.d.ts",
- "default": "./src/browser-setup-tools.ts"
- },
- "./browser-security-runtime": {
- "types": "./dist/src/plugin-sdk/browser-security-runtime.d.ts",
- "default": "./src/browser-security-runtime.ts"
- },
"./channel-secret-runtime": {
"types": "./dist/src/plugin-sdk/channel-secret-runtime.d.ts",
"default": "./src/channel-secret-runtime.ts"
diff --git a/scripts/e2e/npm-telegram-live-docker.sh b/scripts/e2e/npm-telegram-live-docker.sh
index aadc454d06f..1fa6946da86 100755
--- a/scripts/e2e/npm-telegram-live-docker.sh
+++ b/scripts/e2e/npm-telegram-live-docker.sh
@@ -251,8 +251,8 @@ for (const packageJsonPath of [
};
if (!pkg.exports["./plugin-sdk/gateway-runtime"]) {
pkg.exports["./plugin-sdk/gateway-runtime"] = {
- types: "./dist/plugin-sdk/browser-node-runtime.d.ts",
- default: "./dist/plugin-sdk/browser-node-runtime.js",
+ types: "./dist/plugin-sdk/gateway-runtime.d.ts",
+ default: "./dist/plugin-sdk/gateway-runtime.js",
};
}
fs.writeFileSync(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
diff --git a/scripts/lib/config-boundary-guard.mjs b/scripts/lib/config-boundary-guard.mjs
index 7348b1c03e4..d4e4988e5ec 100644
--- a/scripts/lib/config-boundary-guard.mjs
+++ b/scripts/lib/config-boundary-guard.mjs
@@ -9,9 +9,7 @@ const COMPAT_CONFIG_API_FILES = new Set([
"src/config/io.ts",
"src/config/mutate.ts",
"src/memory-host-sdk/runtime-core.ts",
- "src/plugin-sdk/browser-config-runtime.ts",
"src/plugin-sdk/config-runtime.ts",
- "src/plugin-sdk/memory-core.ts",
"src/plugin-sdk/memory-core-host-runtime-core.ts",
"src/plugins/compat/registry.ts",
"src/plugins/contracts/config-boundary-guard.test.ts",
@@ -224,7 +222,7 @@ export function collectDeprecatedInternalConfigApiViolations({
const guards = [
{
pattern:
- /\b(?:import|export)\s+(?:type\s+)?\{[^}]*\bloadConfig\b[^}]*\}\s+from\s+["']openclaw\/plugin-sdk\/(?:browser-config-runtime|config-runtime|memory-core-host-runtime-core)["']/,
+ /\b(?:import|export)\s+(?:type\s+)?\{[^}]*\bloadConfig\b[^}]*\}\s+from\s+["']openclaw\/plugin-sdk\/(?:config-runtime|memory-core-host-runtime-core)["']/,
replacement:
"use getRuntimeConfig(), runtime.config.current(), or pass the already loaded config",
},
@@ -280,13 +278,13 @@ export function collectDeprecatedInternalConfigApiViolations({
const guards = [
{
pattern:
- /\b(?:import|export)\s+(?:type\s+)?\{[\s\S]*?\b(?:loadConfig|writeConfigFile)\b[\s\S]*?\}\s+from\s+["']openclaw\/plugin-sdk\/(?:browser-config-runtime|config-runtime|memory-core-host-runtime-core|memory-core)["']/,
+ /\b(?:import|export)\s+(?:type\s+)?\{[\s\S]*?\b(?:loadConfig|writeConfigFile)\b[\s\S]*?\}\s+from\s+["']openclaw\/plugin-sdk\/(?:config-runtime|memory-core-host-runtime-core)["']/,
replacement:
"use getRuntimeConfig(), runtime.config.current(), or mutation helpers with afterWrite",
},
{
pattern:
- /ReturnType/,
+ /ReturnType/,
replacement: "use OpenClawConfig or the explicit mutation helper type",
},
];
diff --git a/scripts/lib/extension-package-boundary.ts b/scripts/lib/extension-package-boundary.ts
index 8cadd0df2ce..50bf76764c4 100644
--- a/scripts/lib/extension-package-boundary.ts
+++ b/scripts/lib/extension-package-boundary.ts
@@ -25,18 +25,6 @@ export const EXTENSION_PACKAGE_BOUNDARY_BASE_PATHS = {
"openclaw/plugin-sdk/browser-maintenance": [
"../packages/plugin-sdk/dist/extensions/browser/browser-maintenance.d.ts",
],
- "openclaw/plugin-sdk/browser-config-runtime": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-config-runtime.d.ts",
- ],
- "openclaw/plugin-sdk/browser-node-runtime": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-node-runtime.d.ts",
- ],
- "openclaw/plugin-sdk/browser-setup-tools": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-setup-tools.d.ts",
- ],
- "openclaw/plugin-sdk/browser-security-runtime": [
- "../dist/plugin-sdk/src/plugin-sdk/browser-security-runtime.d.ts",
- ],
"openclaw/plugin-sdk/channel-secret-basic-runtime": [
"../packages/plugin-sdk/dist/src/plugin-sdk/channel-secret-basic-runtime.d.ts",
],
diff --git a/scripts/lib/plugin-sdk-entrypoints.json b/scripts/lib/plugin-sdk-entrypoints.json
index a0b66c8ed30..196eacfe897 100644
--- a/scripts/lib/plugin-sdk-entrypoints.json
+++ b/scripts/lib/plugin-sdk-entrypoints.json
@@ -76,7 +76,6 @@
"media-generation-runtime",
"conversation-binding-runtime",
"conversation-runtime",
- "matrix-runtime-shared",
"thread-bindings-runtime",
"thread-bindings-session-runtime",
"text-runtime",
@@ -94,7 +93,6 @@
"secret-file-runtime",
"security-runtime",
"gateway-runtime",
- "github-copilot-token",
"cli-runtime",
"cli-backend",
"agent-harness",
@@ -133,11 +131,6 @@
"allow-from",
"allowlist-config-edit",
"browser-config",
- "browser-config-runtime",
- "browser-config-support",
- "browser-node-runtime",
- "browser-security-runtime",
- "browser-setup-tools",
"boolean-param",
"channel-contract-testing",
"dangerous-name-runtime",
@@ -222,7 +215,6 @@
"persistent-dedupe",
"keyed-async-queue",
"qa-runner-runtime",
- "memory-core",
"memory-core-engine-runtime",
"memory-core-host-engine-embeddings",
"memory-core-host-engine-foundation",
diff --git a/scripts/openclaw-cross-os-release-checks.ts b/scripts/openclaw-cross-os-release-checks.ts
index 09de747daf8..948ce5ddd96 100644
--- a/scripts/openclaw-cross-os-release-checks.ts
+++ b/scripts/openclaw-cross-os-release-checks.ts
@@ -2240,7 +2240,7 @@ export function shouldRunWindowsInstalledBrowserOverrideImportSmoke(platform = p
}
export function buildInstalledBrowserOverrideImportProbeScript(
- runtimeModuleSpecifier = "openclaw/plugin-sdk/browser-node-runtime",
+ runtimeModuleSpecifier = "openclaw/plugin-sdk/plugin-runtime",
) {
return `
import { existsSync } from "node:fs";
@@ -2309,7 +2309,7 @@ async function runInstalledBrowserOverrideImportSmoke(params) {
const startedPath = join(probeDir, "started.txt");
const stoppedPath = join(probeDir, "stopped.txt");
const packageRoot = installedPackageRoot(params.prefixDir);
- const runtimeModulePath = join(packageRoot, "dist", "plugin-sdk", "browser-node-runtime.js");
+ const runtimeModulePath = join(packageRoot, "dist", "plugin-sdk", "plugin-runtime.js");
if (!existsSync(runtimeModulePath)) {
throw new Error(`Installed browser runtime module not found: ${runtimeModulePath}`);
}
diff --git a/scripts/plugin-boundary-report.ts b/scripts/plugin-boundary-report.ts
index f7c421aa754..9bd7cd54bda 100644
--- a/scripts/plugin-boundary-report.ts
+++ b/scripts/plugin-boundary-report.ts
@@ -429,7 +429,7 @@ function buildReport(options: Pick = {}): BoundaryReport {
!usedReserved.has(subpath) &&
matchesOwner(options.owner, resolvePluginOwner(subpath, pluginIds)),
)
- .toSorted();
+ .toSorted((a, b) => a.localeCompare(b));
return {
generatedAt: new Date().toISOString(),
compat: {
diff --git a/src/plugin-sdk/agent-harness-runtime.ts b/src/plugin-sdk/agent-harness-runtime.ts
index 1616f5acc3f..9c01c1c251f 100644
--- a/src/plugin-sdk/agent-harness-runtime.ts
+++ b/src/plugin-sdk/agent-harness-runtime.ts
@@ -66,6 +66,12 @@ export { classifyEmbeddedPiRunResultForModelFallback } from "../agents/pi-embedd
export { resolveEmbeddedAgentRuntime } from "../agents/pi-embedded-runner/runtime.js";
export { resolveUserPath } from "../utils.js";
export { callGatewayTool } from "../agents/tools/gateway.js";
+export type { NodeListNode } from "../agents/tools/nodes-utils.js";
+export {
+ listNodes,
+ resolveNodeIdFromList,
+ selectDefaultNodeFromList,
+} from "../agents/tools/nodes-utils.js";
export { formatToolAggregate } from "../auto-reply/tool-meta.js";
export { isMessagingTool, isMessagingToolSendAction } from "../agents/pi-embedded-messaging.js";
export {
diff --git a/src/plugin-sdk/browser-config-runtime.ts b/src/plugin-sdk/browser-config-runtime.ts
deleted file mode 100644
index 87cd6414d85..00000000000
--- a/src/plugin-sdk/browser-config-runtime.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-export {
- /**
- * @deprecated Use getRuntimeConfig(), runtime.config.current(), or pass the
- * already loaded config through the call path. Runtime code must not reload
- * config on demand. Bundled plugins and repo code are blocked from using
- * this by the deprecated-internal-config-api architecture guard.
- */
- createConfigIO,
- getRuntimeConfig,
- getRuntimeConfigSnapshot,
- /**
- * @deprecated Use getRuntimeConfig(), runtime.config.current(), or pass the
- * already loaded config through the call path. Runtime code must not reload
- * config on demand. Bundled plugins and repo code are blocked from using
- * this by the deprecated-internal-config-api architecture guard.
- */
- loadConfig,
- /**
- * @deprecated Use mutateConfigFile() or replaceConfigFile() with an explicit
- * afterWrite intent so restart behavior stays under host control. Bundled
- * plugins and repo code are blocked from using this by the
- * deprecated-internal-config-api architecture guard.
- */
- writeConfigFile,
- type BrowserConfig,
- type BrowserProfileConfig,
- type OpenClawConfig,
-} from "../config/config.js";
-export { mutateConfigFile, replaceConfigFile } from "../config/mutate.js";
-export { resolveConfigPath, resolveGatewayPort } from "../config/paths.js";
-export {
- DEFAULT_BROWSER_CONTROL_PORT,
- deriveDefaultBrowserCdpPortRange,
- deriveDefaultBrowserControlPort,
-} from "../config/port-defaults.js";
-export { normalizePluginsConfig, resolveEffectiveEnableState } from "../plugins/config-state.js";
-export { parseBooleanValue } from "../utils/boolean.js";
-export { CONFIG_DIR, escapeRegExp, resolveUserPath, shortenHomePath } from "../utils.js";
diff --git a/src/plugin-sdk/browser-config-support.ts b/src/plugin-sdk/browser-config-support.ts
deleted file mode 100644
index 5406d274092..00000000000
--- a/src/plugin-sdk/browser-config-support.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export { resolveGatewayPort } from "../config/paths.js";
-export {
- DEFAULT_BROWSER_CONTROL_PORT,
- deriveDefaultBrowserCdpPortRange,
- deriveDefaultBrowserControlPort,
-} from "../config/port-defaults.js";
-export { isLoopbackHost } from "../gateway/net.js";
-export { CONFIG_DIR, escapeRegExp, resolveUserPath, shortenHomePath } from "../utils.js";
diff --git a/src/plugin-sdk/browser-node-runtime.ts b/src/plugin-sdk/browser-node-runtime.ts
deleted file mode 100644
index 02294b07809..00000000000
--- a/src/plugin-sdk/browser-node-runtime.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export { addGatewayClientOptions, callGatewayFromCli } from "../cli/gateway-rpc.js";
-export type { GatewayRpcOpts } from "../cli/gateway-rpc.js";
-export { runCommandWithRuntime } from "../cli/cli-utils.js";
-export { resolveGatewayAuth } from "../gateway/auth.js";
-export { isLoopbackHost } from "../gateway/net.js";
-export {
- isNodeCommandAllowed,
- resolveNodeCommandAllowlist,
-} from "../gateway/node-command-policy.js";
-export type { NodeSession } from "../gateway/node-registry.js";
-export { ErrorCodes, errorShape } from "../gateway/protocol/index.js";
-export {
- respondUnavailableOnNodeInvokeError,
- safeParseJson,
-} from "../gateway/server-methods/nodes.helpers.js";
-export type { GatewayRequestHandlers } from "../gateway/server-methods/types.js";
-export { ensureGatewayStartupAuth } from "../gateway/startup-auth.js";
-export { rawDataToString } from "../infra/ws.js";
-export {
- startLazyPluginServiceModule,
- type LazyPluginServiceHandle,
-} from "../plugins/lazy-service-module.js";
-export type { OpenClawPluginService } from "../plugins/types.js";
-export { runExec } from "../process/exec.js";
-export { defaultRuntime } from "./runtime.js";
-export { withTimeout } from "../node-host/with-timeout.js";
diff --git a/src/plugin-sdk/browser-security-runtime.ts b/src/plugin-sdk/browser-security-runtime.ts
deleted file mode 100644
index 690e8069660..00000000000
--- a/src/plugin-sdk/browser-security-runtime.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export { hasConfiguredSecretInput } from "../config/types.secrets.js";
-export { extractErrorCode, formatErrorMessage } from "../infra/errors.js";
-export {
- SafeOpenError,
- openFileWithinRoot,
- writeFileFromPathWithinRoot,
-} from "../infra/fs-safe.js";
-export { hasProxyEnvConfigured } from "../infra/net/proxy-env.js";
-export {
- SsrFBlockedError,
- isBlockedHostnameOrIp,
- matchesHostnameAllowlist,
- isPrivateNetworkAllowedByPolicy,
- resolvePinnedHostnameWithPolicy,
- type LookupFn,
- type SsrFPolicy,
-} from "../infra/net/ssrf.js";
-export { normalizeHostname } from "../infra/net/hostname.js";
-export { isNotFoundPathError, isPathInside } from "../infra/path-guards.js";
-export { ensurePortAvailable } from "../infra/ports.js";
-export { generateSecureToken } from "../infra/secure-random.js";
-export { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
-export { createSubsystemLogger } from "../logging/subsystem.js";
-export { redactSensitiveText } from "../logging/redact.js";
-export { wrapExternalContent } from "../security/external-content.js";
-export { safeEqualSecret } from "../security/secret-equal.js";
diff --git a/src/plugin-sdk/browser-setup-tools.ts b/src/plugin-sdk/browser-setup-tools.ts
deleted file mode 100644
index 576a812c49a..00000000000
--- a/src/plugin-sdk/browser-setup-tools.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-export type { AnyAgentTool } from "../agents/tools/common.js";
-export { imageResultFromFile, jsonResult, readStringParam } from "../agents/tools/common.js";
-export type { NodeListNode } from "../agents/tools/nodes-utils.js";
-export {
- listNodes,
- resolveNodeIdFromList,
- selectDefaultNodeFromList,
-} from "../agents/tools/nodes-utils.js";
-export { callGatewayTool } from "../agents/tools/gateway.js";
-export { optionalStringEnum, stringEnum } from "../agents/schema/typebox.js";
-export { formatCliCommand } from "../cli/command-format.js";
-export { inheritOptionFromParent } from "../cli/command-options.js";
-export { formatHelpExamples } from "../cli/help-format.js";
-export { danger, info } from "../globals.js";
-export {
- IMAGE_REDUCE_QUALITY_STEPS,
- buildImageResizeSideGrid,
- getImageMetadata,
- resizeToJpeg,
-} from "../media/image-ops.js";
-export { detectMime } from "../media/mime.js";
-export { ensureMediaDir, saveMediaBuffer } from "../media/store.js";
-export { formatDocsLink } from "../terminal/links.js";
-export { note } from "../terminal/note.js";
-export { theme } from "../terminal/theme.js";
-export { captureEnv, withEnv, withEnvAsync } from "../test-utils/env.js";
-export { withFetchPreconnect } from "../test-utils/fetch-mock.js";
-export type { FetchMock } from "../test-utils/fetch-mock.js";
-export { createTempHomeEnv } from "../test-utils/temp-home.js";
-export type { TempHomeEnv } from "../test-utils/temp-home.js";
-export type { MockFn } from "../test-utils/vitest-mock-fn.js";
diff --git a/src/plugin-sdk/cli-runtime.ts b/src/plugin-sdk/cli-runtime.ts
index fb1dcb0dce0..640b105a49a 100644
--- a/src/plugin-sdk/cli-runtime.ts
+++ b/src/plugin-sdk/cli-runtime.ts
@@ -1,6 +1,9 @@
// Public CLI/output helpers for plugins that share terminal-facing command behavior.
export * from "../cli/command-format.js";
+export { inheritOptionFromParent } from "../cli/command-options.js";
+export { runCommandWithRuntime } from "../cli/cli-utils.js";
+export { formatHelpExamples } from "../cli/help-format.js";
export {
registerCommandGroups,
type CommandGroupEntry,
@@ -10,5 +13,7 @@ export * from "../cli/parse-duration.js";
export { resolveCliArgvInvocation, type CliArgvInvocation } from "../cli/argv-invocation.js";
export { shouldEagerRegisterSubcommands } from "../cli/command-registration-policy.js";
export * from "../cli/wait.js";
+export { note } from "../terminal/note.js";
export { stylePromptTitle } from "../terminal/prompt-style.js";
+export { theme } from "../terminal/theme.js";
export * from "../version.js";
diff --git a/src/plugin-sdk/entrypoints.ts b/src/plugin-sdk/entrypoints.ts
index 37be5a34446..af53ffdc691 100644
--- a/src/plugin-sdk/entrypoints.ts
+++ b/src/plugin-sdk/entrypoints.ts
@@ -6,16 +6,7 @@ export const pluginSdkSubpaths = pluginSdkEntrypoints.filter((entry) => entry !=
// Transitional compatibility/helper surfaces owned by their matching bundled plugin.
// Cross-owner extension imports are blocked by the package contract guardrails.
-export const reservedBundledPluginSdkEntrypoints = [
- "browser-config-runtime",
- "browser-config-support",
- "browser-node-runtime",
- "browser-security-runtime",
- "browser-setup-tools",
- "github-copilot-token",
- "matrix-runtime-shared",
- "memory-core",
-] as const;
+export const reservedBundledPluginSdkEntrypoints = [] as const;
// Supported SDK facades backed by bundled plugins. These are intentionally public
// until they move to generic, plugin-neutral contracts.
diff --git a/src/plugin-sdk/gateway-runtime.ts b/src/plugin-sdk/gateway-runtime.ts
index d7cff644fb7..119efc343d5 100644
--- a/src/plugin-sdk/gateway-runtime.ts
+++ b/src/plugin-sdk/gateway-runtime.ts
@@ -3,6 +3,20 @@
export * from "../gateway/channel-status-patches.js";
export { addGatewayClientOptions, callGatewayFromCli } from "../cli/gateway-rpc.js";
export type { GatewayRpcOpts } from "../cli/gateway-rpc.js";
+export { isLoopbackHost } from "../gateway/net.js";
+export {
+ isNodeCommandAllowed,
+ resolveNodeCommandAllowlist,
+} from "../gateway/node-command-policy.js";
+export type { NodeSession } from "../gateway/node-registry.js";
+export {
+ respondUnavailableOnNodeInvokeError,
+ safeParseJson,
+} from "../gateway/server-methods/nodes.helpers.js";
+export type { GatewayRequestHandlers } from "../gateway/server-methods/types.js";
+export { ensureGatewayStartupAuth } from "../gateway/startup-auth.js";
+export { resolveGatewayAuth } from "../gateway/auth.js";
+export { rawDataToString } from "../infra/ws.js";
export { GatewayClient } from "../gateway/client.js";
export {
createOperatorApprovalsGatewayClient,
diff --git a/src/plugin-sdk/github-copilot-token.ts b/src/plugin-sdk/github-copilot-token.ts
deleted file mode 100644
index 743daf1842e..00000000000
--- a/src/plugin-sdk/github-copilot-token.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "../agents/github-copilot-token.js";
diff --git a/src/plugin-sdk/matrix-runtime-shared.ts b/src/plugin-sdk/matrix-runtime-shared.ts
deleted file mode 100644
index 2fa24c5ec5d..00000000000
--- a/src/plugin-sdk/matrix-runtime-shared.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-// Narrow shared Matrix runtime exports for light runtime-api consumers.
-
-export type {
- ChannelDirectoryEntry,
- ChannelMessageActionContext,
-} from "../channels/plugins/types.public.js";
-export type { OpenClawConfig } from "../config/config.js";
-export { formatZonedTimestamp } from "../infra/format-time/format-datetime.js";
-export type { PluginRuntime, RuntimeLogger } from "../plugins/runtime/types.js";
-export type { RuntimeEnv } from "../runtime.js";
-export type { WizardPrompter } from "../wizard/prompts.js";
diff --git a/src/plugin-sdk/memory-core.ts b/src/plugin-sdk/memory-core.ts
deleted file mode 100644
index 728a8d66449..00000000000
--- a/src/plugin-sdk/memory-core.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-// Narrow plugin-sdk surface for the bundled memory-core plugin.
-// Keep this list additive and scoped to the bundled memory-core surface.
-
-export { getMemorySearchManager, MemoryIndexManager } from "./memory-core-engine-runtime.js";
-export {
- DEFAULT_PI_COMPACTION_RESERVE_TOKENS_FLOOR,
- emptyPluginConfigSchema,
- jsonResult,
- /**
- * @deprecated Use getRuntimeConfig(), runtime.config.current(), or pass the
- * already loaded config through the call path. Runtime code must not reload
- * config on demand. Bundled plugins and repo code are blocked from using
- * this by the deprecated-internal-config-api architecture guard.
- */
- loadConfig,
- parseAgentSessionKey,
- parseNonNegativeByteSize,
- readNumberParam,
- readStringParam,
- resolveCronStyleNow,
- resolveDefaultAgentId,
- resolveMemorySearchConfig,
- resolveSessionAgentId,
- resolveSessionTranscriptsDirForAgent,
- resolveStateDir,
- SILENT_REPLY_TOKEN,
-} from "./memory-core-host-runtime-core.js";
-export type {
- AnyAgentTool,
- MemoryCitationsMode,
- MemoryFlushPlan,
- MemoryFlushPlanResolver,
- MemoryPluginCapability,
- MemoryPluginPublicArtifact,
- MemoryPluginPublicArtifactsProvider,
- MemoryPluginRuntime,
- MemoryPromptSectionBuilder,
- OpenClawConfig,
- OpenClawPluginApi,
-} from "./memory-core-host-runtime-core.js";
-export {
- colorize,
- defaultRuntime,
- formatDocsLink,
- formatErrorMessage,
- formatHelpExamples,
- isRich,
- isVerbose,
- resolveCommandSecretRefsViaGateway,
- setVerbose,
- shortenHomeInString,
- shortenHomePath,
- theme,
- withManager,
- withProgress,
- withProgressTotals,
-} from "./memory-core-host-runtime-cli.js";
-export {
- appendMemoryHostEvent,
- readMemoryHostEvents,
- resolveMemoryHostEventLogPath,
-} from "./memory-core-host-events.js";
-export type { MemoryHostEvent } from "./memory-core-host-events.js";
-export {
- resolveMemoryCorePluginConfig,
- formatMemoryDreamingDay,
- isSameMemoryDreamingDay,
- resolveMemoryDeepDreamingConfig,
- resolveMemoryDreamingConfig,
- resolveMemoryDreamingWorkspaces,
-} from "./memory-core-host-status.js";
-export {
- listMemoryFiles,
- normalizeExtraMemoryPaths,
- readAgentMemoryFile,
- resolveMemoryBackendConfig,
-} from "./memory-core-host-runtime-files.js";
-export type { MemorySearchResult } from "./memory-core-host-runtime-files.js";
diff --git a/src/plugin-sdk/plugin-config-runtime.ts b/src/plugin-sdk/plugin-config-runtime.ts
index c9ec85ce4ed..c6d898ff648 100644
--- a/src/plugin-sdk/plugin-config-runtime.ts
+++ b/src/plugin-sdk/plugin-config-runtime.ts
@@ -1,5 +1,7 @@
import type { OpenClawConfig } from "../config/types.js";
+export { normalizePluginsConfig, resolveEffectiveEnableState } from "../plugins/config-state.js";
+
export function requireRuntimeConfig(config: OpenClawConfig, context: string): OpenClawConfig {
if (config) {
return config;
diff --git a/src/plugin-sdk/security-runtime.ts b/src/plugin-sdk/security-runtime.ts
index 7d847e5f401..60ed1a9e432 100644
--- a/src/plugin-sdk/security-runtime.ts
+++ b/src/plugin-sdk/security-runtime.ts
@@ -9,5 +9,26 @@ export * from "../security/context-visibility.js";
export * from "../security/dm-policy-shared.js";
export * from "../security/external-content.js";
export * from "../security/safe-regex.js";
+export {
+ SafeOpenError,
+ openFileWithinRoot,
+ writeFileFromPathWithinRoot,
+} from "../infra/fs-safe.js";
+export { extractErrorCode, formatErrorMessage } from "../infra/errors.js";
+export { hasProxyEnvConfigured } from "../infra/net/proxy-env.js";
+export { normalizeHostname } from "../infra/net/hostname.js";
+export {
+ SsrFBlockedError,
+ isBlockedHostnameOrIp,
+ isPrivateNetworkAllowedByPolicy,
+ matchesHostnameAllowlist,
+ resolvePinnedHostnameWithPolicy,
+ type LookupFn,
+ type SsrFPolicy,
+} from "../infra/net/ssrf.js";
+export { isNotFoundPathError, isPathInside } from "../infra/path-guards.js";
+export { ensurePortAvailable } from "../infra/ports.js";
+export { generateSecureToken } from "../infra/secure-random.js";
+export { resolvePreferredOpenClawTmpDir } from "../infra/tmp-openclaw-dir.js";
export { redactSensitiveText } from "../logging/redact.js";
export { safeEqualSecret } from "../security/secret-equal.js";
diff --git a/src/plugins/contracts/extension-package-project-boundaries.test.ts b/src/plugins/contracts/extension-package-project-boundaries.test.ts
index 13b4188f623..2a227271a5d 100644
--- a/src/plugins/contracts/extension-package-project-boundaries.test.ts
+++ b/src/plugins/contracts/extension-package-project-boundaries.test.ts
@@ -129,17 +129,8 @@ describe("opt-in extension package boundaries", () => {
expect(packageJson.exports?.["./acp-runtime"]?.types).toBe(
"./dist/src/plugin-sdk/acp-runtime.d.ts",
);
- expect(packageJson.exports?.["./browser-config-runtime"]?.types).toBe(
- "./dist/src/plugin-sdk/browser-config-runtime.d.ts",
- );
- expect(packageJson.exports?.["./browser-node-runtime"]?.types).toBe(
- "./dist/src/plugin-sdk/browser-node-runtime.d.ts",
- );
- expect(packageJson.exports?.["./browser-setup-tools"]?.types).toBe(
- "./dist/src/plugin-sdk/browser-setup-tools.d.ts",
- );
- expect(packageJson.exports?.["./browser-security-runtime"]?.types).toBe(
- "./dist/src/plugin-sdk/browser-security-runtime.d.ts",
+ expect(packageJson.exports?.["./browser-config"]?.types).toBe(
+ "./dist/src/plugin-sdk/browser-config.d.ts",
);
expect(packageJson.exports?.["./channel-secret-runtime"]?.types).toBe(
"./dist/src/plugin-sdk/channel-secret-runtime.d.ts",
diff --git a/src/plugins/contracts/plugin-sdk-index.bundle.test.ts b/src/plugins/contracts/plugin-sdk-index.bundle.test.ts
index 785cb185b5c..93301a0ccdc 100644
--- a/src/plugins/contracts/plugin-sdk-index.bundle.test.ts
+++ b/src/plugins/contracts/plugin-sdk-index.bundle.test.ts
@@ -9,7 +9,7 @@ import { resolveBundledPluginFile } from "./test-helpers/bundled-plugin-roots.js
const require = createRequire(import.meta.url);
const tsdownModuleUrl = pathToFileURL(require.resolve("tsdown")).href;
-const bundledRepresentativeEntrypoints = ["matrix-runtime-shared"] as const;
+const bundledRepresentativeEntrypoints = ["browser-config"] as const;
const bundleTempRootTracker = createSuiteTempRootTracker(
"openclaw-plugin-sdk-build",
path.join(process.cwd(), "node_modules", ".cache"),
diff --git a/src/plugins/contracts/plugin-sdk-subpaths.test.ts b/src/plugins/contracts/plugin-sdk-subpaths.test.ts
index 4437a6f573b..160bf2cb578 100644
--- a/src/plugins/contracts/plugin-sdk-subpaths.test.ts
+++ b/src/plugins/contracts/plugin-sdk-subpaths.test.ts
@@ -1069,7 +1069,6 @@ describe("plugin-sdk subpath exports", () => {
]);
expectSourceOmitsImportPattern("command-auth", "../auto-reply/status.js");
expectSourceOmitsSnippet("command-auth", "../../extensions/");
- expectSourceOmitsSnippet("matrix-runtime-shared", "../../extensions/");
expectSourceMentions("channel-send-result", [
"attachChannelToResult",
"buildChannelSendResult",
@@ -1108,7 +1107,6 @@ describe("plugin-sdk subpath exports", () => {
"unregisterSessionBindingAdapter",
"SessionBindingAdapter",
]);
- expectSourceMentions("matrix-runtime-shared", ["formatZonedTimestamp"]);
expectSourceMentions("ssrf-runtime", [
"closeDispatcher",
"createPinnedDispatcher",
diff --git a/test/scripts/npm-telegram-live.test.ts b/test/scripts/npm-telegram-live.test.ts
index 493077eb333..070d02cbd21 100644
--- a/test/scripts/npm-telegram-live.test.ts
+++ b/test/scripts/npm-telegram-live.test.ts
@@ -75,10 +75,9 @@ describe("package Telegram live Docker E2E", () => {
expect(script).toContain('pkg.exports["./plugin-sdk/qa-channel-protocol"]');
expect(script).toContain('"./extensions/qa-channel/src/protocol.ts"');
expect(script).toContain('pkg.exports["./plugin-sdk/gateway-runtime"]');
- expect(script).toContain('"./dist/plugin-sdk/browser-node-runtime.js"');
+ expect(script).toContain('"./dist/plugin-sdk/gateway-runtime.js"');
expect(gatewayRpcClient).toContain('from "openclaw/plugin-sdk/gateway-runtime"');
expect(qaRuntimeApi).toContain('from "openclaw/plugin-sdk/gateway-runtime"');
- expect(gatewayRpcClient).not.toContain('from "openclaw/plugin-sdk/browser-node-runtime"');
});
it("exposes installed package dependencies to the mounted QA harness", () => {
diff --git a/test/scripts/openclaw-cross-os-release-checks.test.ts b/test/scripts/openclaw-cross-os-release-checks.test.ts
index ee77e1048ef..69d027c7ea4 100644
--- a/test/scripts/openclaw-cross-os-release-checks.test.ts
+++ b/test/scripts/openclaw-cross-os-release-checks.test.ts
@@ -326,17 +326,17 @@ describe("scripts/openclaw-cross-os-release-checks", () => {
expect(shouldRunWindowsInstalledBrowserOverrideImportSmoke("linux")).toBe(false);
const script = buildInstalledBrowserOverrideImportProbeScript();
- expect(script).toContain('from "openclaw/plugin-sdk/browser-node-runtime"');
+ expect(script).toContain('from "openclaw/plugin-sdk/plugin-runtime"');
expect(script).toContain('overrideEnvVar: "OPENCLAW_BROWSER_CONTROL_MODULE"');
expect(script).toContain("startBrowserControlService");
expect(script).toContain("stopBrowserControlService");
expect(script).toContain("Browser control override start sentinel was not written.");
const installedScript = buildInstalledBrowserOverrideImportProbeScript(
- "file:///C:/Users/runner/AppData/Roaming/npm/node_modules/openclaw/dist/plugin-sdk/browser-node-runtime.js",
+ "file:///C:/Users/runner/AppData/Roaming/npm/node_modules/openclaw/dist/plugin-sdk/plugin-runtime.js",
);
expect(installedScript).toContain(
- 'from "file:///C:/Users/runner/AppData/Roaming/npm/node_modules/openclaw/dist/plugin-sdk/browser-node-runtime.js"',
+ 'from "file:///C:/Users/runner/AppData/Roaming/npm/node_modules/openclaw/dist/plugin-sdk/plugin-runtime.js"',
);
expect(readFileSync("scripts/openclaw-cross-os-release-checks.ts", "utf8")).toContain(
"OPENCLAW_BROWSER_CONTROL_MODULE: pathToFileURL(overridePath).href",