refactor(plugin-sdk): retire reserved helper exports

This commit is contained in:
Peter Steinberger
2026-04-28 05:21:26 +01:00
parent 870d993eb8
commit af7f651db3
85 changed files with 546 additions and 465 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -313,11 +313,10 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
</Accordion>
<Accordion title="Reserved bundled-helper subpaths">
| 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`.
</Accordion>
</AccordionGroup>

View File

@@ -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 {

View File

@@ -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<typeof import("openclaw/plugin-sdk/browser-setup-tools")>(
"openclaw/plugin-sdk/browser-setup-tools",
);
vi.mock("./sdk-setup-tools.js", async () => {
const actual =
await vi.importActual<typeof import("./sdk-setup-tools.js")>("./sdk-setup-tools.js");
return {
...actual,
callGatewayTool: gatewayMocks.callGatewayTool,

View File

@@ -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,

View File

@@ -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";

View File

@@ -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"]);

View File

@@ -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";

View File

@@ -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,

View File

@@ -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(() => ({

View File

@@ -16,10 +16,9 @@ const gatewayMocks = vi.hoisted(() => ({
})),
}));
vi.mock("openclaw/plugin-sdk/browser-node-runtime", async () => {
const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/browser-node-runtime")>(
"openclaw/plugin-sdk/browser-node-runtime",
);
vi.mock("../sdk-node-runtime.js", async () => {
const actual =
await vi.importActual<typeof import("../sdk-node-runtime.js")>("../sdk-node-runtime.js");
return {
...actual,
callGatewayFromCli: gatewayMocks.callGatewayFromCli,

View File

@@ -1 +1 @@
export { formatCliCommand } from "openclaw/plugin-sdk/browser-setup-tools";
export { formatCliCommand } from "../sdk-setup-tools.js";

View File

@@ -5,4 +5,4 @@ export {
type BrowserConfig,
type BrowserProfileConfig,
type OpenClawConfig,
} from "openclaw/plugin-sdk/browser-config-runtime";
} from "../sdk-config.js";

View File

@@ -1 +1 @@
export { resolveGatewayPort } from "openclaw/plugin-sdk/browser-config-support";
export { resolveGatewayPort } from "../sdk-config.js";

View File

@@ -2,4 +2,4 @@ export {
DEFAULT_BROWSER_CONTROL_PORT,
deriveDefaultBrowserCdpPortRange,
deriveDefaultBrowserControlPort,
} from "openclaw/plugin-sdk/browser-config-support";
} from "../sdk-config.js";

View File

@@ -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";

View File

@@ -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 = [

View File

@@ -1 +1 @@
export { resolveGatewayAuth } from "openclaw/plugin-sdk/browser-node-runtime";
export { resolveGatewayAuth } from "../sdk-node-runtime.js";

View File

@@ -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<typeof import("openclaw/plugin-sdk/browser-node-runtime")>(
"openclaw/plugin-sdk/browser-node-runtime",
);
vi.mock("../sdk-node-runtime.js", async () => {
const actual =
await vi.importActual<typeof import("../sdk-node-runtime.js")>("../sdk-node-runtime.js");
return {
...actual,
isNodeCommandAllowed: isNodeCommandAllowedMock,

View File

@@ -1 +1 @@
export { isLoopbackHost } from "openclaw/plugin-sdk/browser-config-support";
export { isLoopbackHost } from "../sdk-node-runtime.js";

View File

@@ -1 +1 @@
export { ensureGatewayStartupAuth } from "openclaw/plugin-sdk/browser-node-runtime";
export { ensureGatewayStartupAuth } from "../sdk-node-runtime.js";

View File

@@ -1 +1 @@
export { extractErrorCode, formatErrorMessage } from "openclaw/plugin-sdk/browser-security-runtime";
export { extractErrorCode, formatErrorMessage } from "../sdk-security-runtime.js";

View File

@@ -2,4 +2,4 @@ export {
SafeOpenError,
openFileWithinRoot,
writeFileFromPathWithinRoot,
} from "openclaw/plugin-sdk/browser-security-runtime";
} from "../sdk-security-runtime.js";

View File

@@ -1 +1 @@
export { hasProxyEnvConfigured } from "openclaw/plugin-sdk/browser-security-runtime";
export { hasProxyEnvConfigured } from "../../sdk-security-runtime.js";

View File

@@ -4,4 +4,4 @@ export {
resolvePinnedHostnameWithPolicy,
type LookupFn,
type SsrFPolicy,
} from "openclaw/plugin-sdk/browser-security-runtime";
} from "../../sdk-security-runtime.js";

View File

@@ -1 +1 @@
export { isNotFoundPathError, isPathInside } from "openclaw/plugin-sdk/browser-security-runtime";
export { isNotFoundPathError, isPathInside } from "../sdk-security-runtime.js";

View File

@@ -1 +1 @@
export { ensurePortAvailable } from "openclaw/plugin-sdk/browser-security-runtime";
export { ensurePortAvailable } from "../sdk-security-runtime.js";

View File

@@ -1 +1 @@
export { generateSecureToken } from "openclaw/plugin-sdk/browser-security-runtime";
export { generateSecureToken } from "../sdk-security-runtime.js";

View File

@@ -1 +1 @@
export { redactSensitiveText } from "openclaw/plugin-sdk/browser-security-runtime";
export { redactSensitiveText } from "../sdk-security-runtime.js";

View File

@@ -3,4 +3,4 @@ export {
buildImageResizeSideGrid,
getImageMetadata,
resizeToJpeg,
} from "openclaw/plugin-sdk/browser-setup-tools";
} from "../sdk-setup-tools.js";

View File

@@ -1 +1 @@
export { ensureMediaDir, saveMediaBuffer } from "openclaw/plugin-sdk/browser-setup-tools";
export { ensureMediaDir, saveMediaBuffer } from "../sdk-setup-tools.js";

View File

@@ -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<unknown>,
@@ -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"),
}));

View File

@@ -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;

View File

@@ -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({

View File

@@ -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,
}));

View File

@@ -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;

View File

@@ -1 +1 @@
export { runExec } from "openclaw/plugin-sdk/browser-node-runtime";
export { runExec } from "../sdk-node-runtime.js";

View File

@@ -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<string>(DEFAULT_TRUTHY);
const DEFAULT_FALSY_SET = new Set<string>(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;
}

View File

@@ -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<T>(
work: (signal: AbortSignal | undefined) => Promise<T>,
timeoutMs?: number,
label?: string,
): Promise<T> {
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<never> = 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);
}
}
}

View File

@@ -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";

View File

@@ -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";

View File

@@ -1 +1 @@
export { safeEqualSecret } from "openclaw/plugin-sdk/browser-security-runtime";
export { safeEqualSecret } from "../sdk-security-runtime.js";

View File

@@ -1 +1,3 @@
export type { MockFn } from "openclaw/plugin-sdk/browser-setup-tools";
// oxlint-disable-next-line typescript/no-explicit-any
export type MockFn<T extends (...args: any[]) => any = (...args: any[]) => any> =
import("vitest").Mock<T>;

View File

@@ -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";

View File

@@ -1 +1 @@
export { parseBooleanValue } from "openclaw/plugin-sdk/browser-config-runtime";
export { parseBooleanValue } from "../sdk-config.js";

View File

@@ -0,0 +1,16 @@
import { vi } from "vitest";
vi.mock("../src/sdk-security-runtime.js", async () => {
const actual = await vi.importActual<typeof import("../src/sdk-security-runtime.js")>(
"../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 }),
};
});

View File

@@ -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,
}));

View File

@@ -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";

View File

@@ -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<string, string> {
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<string, unknown>;
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,
};
}

View File

@@ -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.

View File

@@ -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,

View File

@@ -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";

View File

@@ -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,

View File

@@ -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,

View File

@@ -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";

View File

@@ -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"
],

View File

@@ -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"
],

View File

@@ -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"

View File

@@ -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"

View File

@@ -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`);

View File

@@ -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<typeof import\(["']openclaw\/plugin-sdk\/(?:browser-config-runtime|config-runtime|memory-core-host-runtime-core|memory-core)["']\)\.(?:loadConfig|writeConfigFile)>/,
/ReturnType<typeof import\(["']openclaw\/plugin-sdk\/(?:config-runtime|memory-core-host-runtime-core)["']\)\.(?:loadConfig|writeConfigFile)>/,
replacement: "use OpenClawConfig or the explicit mutation helper type",
},
];

View File

@@ -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",
],

View File

@@ -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",

View File

@@ -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}`);
}

View File

@@ -429,7 +429,7 @@ function buildReport(options: Pick<CliOptions, "owner"> = {}): BoundaryReport {
!usedReserved.has(subpath) &&
matchesOwner(options.owner, resolvePluginOwner(subpath, pluginIds)),
)
.toSorted();
.toSorted((a, b) => a.localeCompare(b));
return {
generatedAt: new Date().toISOString(),
compat: {

View File

@@ -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 {

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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.

View File

@@ -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,

View File

@@ -1 +0,0 @@
export * from "../agents/github-copilot-token.js";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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;

View File

@@ -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";

View File

@@ -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",

View File

@@ -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"),

View File

@@ -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",

View File

@@ -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", () => {

View File

@@ -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",