refactor: retire due compat-ledger surfaces (context-engine host params, deactivate alias, logging internals) (#121845)

* refactor(plugins): retire deactivate hook alias

* refactor(plugin-sdk): prune retired facade exports

* test(logging): isolate logger test controls

* refactor(logging): internalize file transport controls

* test(plugin-sdk): preserve retired facade coverage

* test(auto-reply): remove stale diagnostic imports

* refactor(logging): delete dead config-read guard

shouldSkipMutatingLoggingConfigRead had no production caller even on main;
it survived the dead-export scan only via logger's testApi re-export. The
test-isolation commit removed that mask, exposing the fossil. Delete the
guard, its test-only re-export, its mock entry, and its dedicated test file.

* refactor(plugin-sdk): retire due compatibility subpaths

* test(plugin-sdk): type group policy predicates

* refactor(plugin-sdk): split removed subpath records

* refactor(secrets): remove retired collector barrel

* test(plugin-sdk): tighten wildcard surface pin

* refactor(plugin-sdk): retire matrix facade metadata

* style(plugin-sdk): format facade metadata

* fix(ci): load channel setup contracts from source

Repair the main-owned regression from 99d662473c (Peter Steinberger): the new env-contract test could consume stale ignored dist metadata instead of the checked-in plugin declaration.

* test(plugin-sdk): refresh API baseline after rebase
This commit is contained in:
Peter Steinberger
2026-08-12 12:41:27 -07:00
committed by GitHub
parent 49092ebab3
commit dceb2c343c
116 changed files with 562 additions and 1557 deletions
+6 -1
View File
@@ -70,7 +70,7 @@ let missing = 0;
`import { buildChannelConfigSchema, DmPolicySchema } from "openclaw/plugin-sdk/channel-config-schema";
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
import { createPluginRuntimeStore, type PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
import { z } from "openclaw/plugin-sdk/zod";
import { z } from "zod";
const runtimeStore = createPluginRuntimeStore<PluginRuntime>({
pluginId: "package-consumer",
@@ -110,6 +110,11 @@ export default defineChannelPluginEntry({
const openclawPackagePath = join(consumerRoot, "node_modules", "openclaw");
mkdirSync(dirname(openclawPackagePath), { recursive: true });
symlinkSync(repoRoot, openclawPackagePath, process.platform === "win32" ? "junction" : "dir");
symlinkSync(
join(repoRoot, "node_modules", "zod"),
join(consumerRoot, "node_modules", "zod"),
process.platform === "win32" ? "junction" : "dir",
);
const result = spawnSync(
process.execPath,
@@ -51,8 +51,4 @@ export const BANNED_INTERNAL_PLUGIN_SDK_FACADE_MODULES: BannedInternalPluginSdkF
modulePath: "src/plugin-sdk/inbound-envelope",
canonical: "openclaw/plugin-sdk/channel-inbound",
},
{
modulePath: "src/plugin-sdk/text-runtime",
canonical: "the focused typed public Plugin SDK subpath for the imported helper",
},
];
@@ -64,8 +64,6 @@ export const EXTENSION_PACKAGE_BOUNDARY_BASE_PATHS = {
"openclaw/plugin-sdk/channel-secret-basic-runtime": [
"../dist/plugin-sdk/channel-secret-basic-runtime.d.ts",
],
"openclaw/plugin-sdk/channel-secret-runtime": ["../dist/plugin-sdk/channel-secret-runtime.d.ts"],
"openclaw/plugin-sdk/channel-streaming": ["../dist/plugin-sdk/channel-streaming.d.ts"],
"openclaw/plugin-sdk/error-runtime": ["../dist/plugin-sdk/error-runtime.d.ts"],
"openclaw/plugin-sdk/secret-ref-runtime": ["../dist/plugin-sdk/secret-ref-runtime.d.ts"],
"openclaw/plugin-sdk/ssrf-runtime": ["../dist/plugin-sdk/ssrf-runtime.d.ts"],
@@ -1,5 +1,4 @@
[
"channel-lifecycle",
"infra-runtime",
"text-runtime"
"infra-runtime"
]
@@ -1,21 +1,13 @@
[
"agent-media-payload",
"agent-config-primitives",
"channel-lifecycle",
"channel-logging",
"channel-message",
"channel-reply-pipeline",
"channel-secret-runtime",
"channel-streaming",
"command-auth",
"config-runtime",
"discord",
"group-access",
"inbound-reply-dispatch",
"infra-runtime",
"matrix",
"messaging-targets",
"telegram-account",
"text-runtime",
"zod"
"telegram-account"
]
+1 -5
View File
@@ -111,11 +111,7 @@ export const deprecatedBarrelPluginSdkEntrypoints = pluginSdkSubpaths.filter((en
);
/** Supported SDK facades backed by bundled plugins until generic contracts replace them. */
export const supportedBundledFacadeSdkEntrypoints = [
"discord",
"matrix",
"telegram-account",
] as const;
export const supportedBundledFacadeSdkEntrypoints = ["discord", "telegram-account"] as const;
/** Plugin-owned surfaces intentionally public and documented for third-party plugins. */
export const publicPluginOwnedSdkEntrypoints = ["memory-core-host-engine-foundation"] as const;
-8
View File
@@ -18,7 +18,6 @@
"setup",
"setup-runtime",
"channel-setup",
"channel-streaming",
"channel-streaming-config",
"setup-tools",
"archive",
@@ -90,7 +89,6 @@
"conversation-runtime",
"thread-bindings-runtime",
"thread-bindings-session-runtime",
"text-runtime",
"text-chunking",
"agent-scope-runtime",
"agent-runtime",
@@ -101,7 +99,6 @@
"plugin-command-runtime",
"plugin-runtime",
"channel-secret-basic-runtime",
"channel-secret-runtime",
"channel-secret-tts-runtime",
"secret-ref-runtime",
"secret-file-runtime",
@@ -158,7 +155,6 @@
"account-id",
"account-resolution",
"account-resolution-runtime",
"agent-config-primitives",
"access-groups",
"allow-from",
"allowlist-config-edit",
@@ -177,7 +173,6 @@
"collection-runtime",
"direct-dm-guard-policy",
"discord",
"matrix",
"device-bootstrap",
"diagnostic-runtime",
"error-runtime",
@@ -196,7 +191,6 @@
"channel-feedback",
"channel-inbound",
"channel-inbound-debounce",
"channel-logging",
"channel-mention-gating",
"channel-lifecycle",
"channel-ingress-runtime",
@@ -228,7 +222,6 @@
"ssrf-dispatcher",
"string-coerce-runtime",
"group-activation",
"group-access",
"global-singleton",
"directory-config-runtime",
"directory-runtime",
@@ -332,7 +325,6 @@
"webhook-targets",
"webhook-request-guards",
"web-media",
"zod",
"agent-core",
"agent-sessions",
"llm"
+1 -100
View File
@@ -15,14 +15,7 @@ import {
import { builtinModules } from "node:module";
import { createRequire } from "node:module";
import { tmpdir } from "node:os";
import {
dirname,
isAbsolute,
join,
posix as pathPosix,
relative,
win32 as pathWin32,
} from "node:path";
import { isAbsolute, join, posix as pathPosix, relative, win32 as pathWin32 } from "node:path";
import { pathToFileURL } from "node:url";
import { expectDefined } from "../packages/normalization-core/src/expect.js";
import { ALWAYS_ALLOWED_RUNTIME_DIR_NAMES } from "../src/plugin-sdk/facade-activation-contract.ts";
@@ -469,7 +462,6 @@ export function collectInstalledPackageErrors(params: {
errors.push(...collectInstalledBundledExtensionManifestErrors(params.packageRoot));
errors.push(...collectInstalledAlwaysAllowedRuntimeFacadeErrors(params.packageRoot));
errors.push(...collectInstalledContextEngineRuntimeErrors(params.packageRoot));
errors.push(...collectInstalledPluginSdkZodArtifactErrors(params.packageRoot));
errors.push(...collectInstalledPluginSdkDeclarationErrors(params.packageRoot));
errors.push(...collectInstalledRootDependencyManifestErrors(params.packageRoot));
@@ -613,97 +605,6 @@ export function collectInstalledContextEngineRuntimeErrors(packageRoot: string):
return errors;
}
function resolveInstalledDistRelativeImport(params: {
distRoot: string;
importerPath: string;
specifier: string;
}): string | null {
if (!params.specifier.startsWith(".")) {
return null;
}
const candidatePath = join(dirname(params.importerPath), params.specifier);
const candidatePaths = [
candidatePath,
`${candidatePath}.js`,
`${candidatePath}.mjs`,
`${candidatePath}.cjs`,
join(candidatePath, "index.js"),
join(candidatePath, "index.mjs"),
join(candidatePath, "index.cjs"),
];
for (const resolvedPath of candidatePaths) {
const relativePath = relative(params.distRoot, resolvedPath);
if (
relativePath.length === 0 ||
relativePath.startsWith("..") ||
isAbsolute(relativePath) ||
!existsSync(resolvedPath)
) {
continue;
}
return resolvedPath;
}
return null;
}
export function collectInstalledPluginSdkZodArtifactErrors(packageRoot: string): string[] {
const distRoot = join(packageRoot, "dist");
const entryRelativePath = "dist/plugin-sdk/zod.js";
const entryPath = join(packageRoot, entryRelativePath);
const pending = [entryPath];
const visited = new Set<string>();
while (pending.length > 0) {
const filePath = pending.pop();
if (!filePath || visited.has(filePath)) {
continue;
}
visited.add(filePath);
if (!existsSync(filePath)) {
return [`installed package is missing required plugin SDK artifact: ${entryRelativePath}`];
}
const relativePath = relative(packageRoot, filePath).replaceAll("\\", "/");
const fileStat = lstatSync(filePath);
if (!fileStat.isFile() || fileStat.size > MAX_INSTALLED_ROOT_DIST_JS_BYTES) {
return [
`installed package plugin SDK artifact '${relativePath}' is invalid or exceeds ${MAX_INSTALLED_ROOT_DIST_JS_BYTES} bytes.`,
];
}
const source = readFileSync(filePath, "utf8");
const parsedSpecifiers = extractJavaScriptImportSpecifiers(source);
if (!parsedSpecifiers.ok) {
return [
`installed package plugin SDK artifact '${relativePath}' could not be parsed for runtime dependency verification: ${parsedSpecifiers.error}.`,
];
}
for (const specifier of parsedSpecifiers.specifiers) {
if (specifier === "zod" || specifier.startsWith("zod/")) {
return [
`installed package plugin SDK zod artifact must be self-contained but ${relativePath} imports ${specifier}.`,
];
}
const resolvedPath = resolveInstalledDistRelativeImport({
distRoot,
importerPath: filePath,
specifier,
});
if (resolvedPath) {
pending.push(resolvedPath);
}
}
}
return [];
}
function collectInstalledPluginSdkDeclarationErrors(packageRoot: string): string[] {
const pluginSdkDistRoot = join(packageRoot, "dist", "plugin-sdk");
const errors: string[] = [];
+5 -17
View File
@@ -122,7 +122,6 @@ const defaultPublicDeprecatedExportsByEntrypointBudget = Object.freeze({
health: 0,
// +1: shipped channel setup state-migration declaration during its migration window.
"channel-entry-contract": 1,
"channel-streaming": 54,
"approval-gateway-runtime": 1,
"approval-handler-runtime": 1,
"approval-reply-runtime": 0,
@@ -141,22 +140,16 @@ const defaultPublicDeprecatedExportsByEntrypointBudget = Object.freeze({
"agent-media-payload": 3,
// +2: deprecated media projection type and builder.
"reply-payload": 2,
// +1: flushLogger projected through the deprecated text-runtime barrel.
"text-runtime": 192,
"agent-runtime": 2,
"channel-secret-runtime": 23,
// +4: session-write lease no-op compatibility stubs through the 2026.10 train.
// +4: legacy AgentHarness, attempt, embedded-run, and side-question contracts remain
// deprecated while external harnesses migrate to required-capability V2 contracts.
"agent-harness": 2,
"agent-harness-runtime": 12,
"agent-config-primitives": 2,
"command-auth": 78,
discord: 47,
matrix: 1,
// +4: deprecated media projection type, builder, and turn aliases.
"channel-inbound": 18,
"channel-logging": 4,
"channel-lifecycle": 23,
// +1: shared ingress error factory projected through the deprecated message barrel.
// +1: shared ingress retention defaults projected through the deprecated message barrel.
@@ -169,12 +162,10 @@ const defaultPublicDeprecatedExportsByEntrypointBudget = Object.freeze({
"session-store-runtime": 4,
// +2: shipped Slack and Discord setup helpers retained through their package migration window.
"setup-runtime": 2,
"group-access": 13,
"reply-history": 6,
"messaging-targets": 12,
"provider-auth": 19,
"telegram-account": 3,
zod: 282,
} satisfies Record<string, number>);
export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env) {
@@ -194,7 +185,7 @@ export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env
// +1: dependency-light channel streaming config readers for doctor closures
// (realtime-voice-activation is private-local and not counted here).
// +1: registry-bound plugin command planning and exact selected execution.
152,
144,
env,
),
publicExports: readPluginSdkSurfaceBudgetEnv(
@@ -275,7 +266,7 @@ export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env
// +2: narrow channel agent-run terminal reader and outcome contract.
// +5: narrow string, record, and error coercion helpers.
// +1: normalized Gateway public origin resolver for plugin-generated links.
4879,
4308,
env,
),
publicFunctionExports: readPluginSdkSurfaceBudgetEnv(
@@ -342,7 +333,7 @@ export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env
// +1: narrow channel agent-run terminal reader.
// +5: narrow string, record, and error coercion helpers.
// +1: normalized Gateway public origin resolver for plugin-generated links.
2932,
2572,
env,
),
publicDeprecatedExports: readPluginSdkSurfaceBudgetEnv(
@@ -351,24 +342,21 @@ export function readPluginSdkSurfaceBudgets(env: NodeJS.ProcessEnv = process.env
// +2: shipped Slack and Discord setup compatibility helpers.
// +10: named media legacy projection deprecations across public compatibility barrels.
// +2: channel prompt-context type and metadata builder compatibility aliases.
// +1: flushLogger projected through the deprecated text-runtime barrel.
// +1: shared ingress error factory projected through channel-message.
// +1: shared ingress retention defaults projected through channel-message.
// +1: shipped channel setup state-migration declaration during its migration window.
// +4: session-write lease no-op compatibility stubs through the 2026.10 train.
// +7: restore still-existing deprecated inbound-dispatch compatibility re-exports.
// +6: source-compatible harness contracts retained during the V2 migration window.
1716,
1142,
env,
),
publicWildcardReexports: readPluginSdkSurfaceBudgetEnv(
"OPENCLAW_PLUGIN_SDK_MAX_PUBLIC_WILDCARD_REEXPORTS",
// -1: text-runtime now names its global-singleton exports explicitly.
// -1: infra-runtime now names its error exports explicitly.
// -1: infra-runtime excludes the internal system-event receipt API.
// -2: text-runtime names record and string coercion compatibility exports explicitly.
// -1: infra-runtime re-exports number coercion directly from its canonical owner.
75,
50,
env,
),
};