mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
chore(compat): date the annotated deprecation families and expose removal-pending debt (#114002)
* chore(compat): date the annotated deprecation families and expose removal-pending debt Adds 10 dated compat-registry records for shipped deprecated surfaces that previously had @deprecated annotations only (removeAfter 2026-10-01 per the approved 60-day window), extends the beta5 session-store record with the package-root aliases, surfaces removal-pending records with due dates, blockers, and readers in the plugin boundary report, and converts undated cleanup obligations (CI timing job, zizmor excessive-permissions, staged Codex CI auth, memory-host legacy state dir, agent-DB schema-ladder floors) into dated markers visible to the weekly dated-TODO sweep. Metadata, diagnostics, and docs only - no runtime behavior change. * fix(compat): keep extension src test paths out of core string literals The core import guardrail forbids extensions/*/src/ path shapes in core production string literals; cite the package-root google-meet test and the registry test for official-plugin-export-aliases instead.
This commit is contained in:
committed by
GitHub
parent
69399b1cc3
commit
b2f6ecc2a9
@@ -3544,7 +3544,7 @@ jobs:
|
||||
- macos-swift
|
||||
- ios-build
|
||||
- android
|
||||
# Re-enable this job when we want to collect CI timing data for timing optimization.
|
||||
# TODO(2026-10-01): Re-enable or delete the CI timing-summary job after the next timing-optimization review.
|
||||
if: ${{ false && !cancelled() && always() && github.event_name != 'push' && (github.event_name != 'pull_request' || !github.event.pull_request.draft) }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
|
||||
@@ -3326,7 +3326,8 @@ jobs:
|
||||
echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
|
||||
;;
|
||||
live-codex-harness*-docker)
|
||||
# Keep CI on the API-key path for now. The staged Codex auth secret
|
||||
# TODO(2026-10-01): Repair or remove stale staged Codex auth, then choose the canonical CI auth path.
|
||||
# Keep CI on the API-key path. The staged Codex auth secret
|
||||
# is currently stale, but the wrapper still supports codex-auth for
|
||||
# local maintainer reruns without changing Peter's flow.
|
||||
echo "OPENCLAW_LIVE_CODEX_HARNESS_AUTH=api-key" >> "$GITHUB_ENV"
|
||||
|
||||
+1
-2
@@ -7,8 +7,7 @@ rules:
|
||||
unpinned-uses:
|
||||
disable: true
|
||||
|
||||
# Disable excessive-permissions for now - adding explicit permissions
|
||||
# blocks requires careful review of each workflow's needs
|
||||
# TODO(2026-10-01): Re-enable excessive-permissions after each workflow has an explicit permission review.
|
||||
excessive-permissions:
|
||||
disable: true
|
||||
|
||||
|
||||
@@ -78,11 +78,37 @@ The remaining dated compatibility areas are:
|
||||
- embedded Pi agent aliases
|
||||
- the shipped agent-harness SDK aliases, whose removal is pending a new
|
||||
externally documented migration decision
|
||||
- the October 2026 SDK annotation families listed below
|
||||
|
||||
Active, undated registry records cover supported behavior rather than removal
|
||||
debt, including activation hints, plugin capture, bundled plugin enablement,
|
||||
and the generated channel-config fallback.
|
||||
|
||||
The annotation-only compatibility audit added these dated records. Their
|
||||
`removeAfter` date is an earliest review date, not permission to remove a
|
||||
surface while its stated reader or migration condition remains unmet.
|
||||
|
||||
| Compatibility code | Removal condition | `removeAfter` |
|
||||
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------- |
|
||||
| `plugin-sdk-channel-setup-input-fields` | Repeat the published-plugin artifact sweep and remove only fields with no reader. | 2026-10-01 |
|
||||
| `plugin-sdk-broad-runtime-barrels` | Move bundled and indexed external consumers to focused SDK subpaths. | 2026-10-01 |
|
||||
| `plugin-sdk-provider-owned-helper-shims` | Move each deprecated provider helper to its provider-local API and prove no published reader remains. | 2026-10-01 |
|
||||
| `message-presentation-legacy-bridges` | Move reply producers and official channel packages to `MessagePresentation`. | 2026-10-01 |
|
||||
| `plugin-sdk-focused-compat-aliases` | Prove every enumerated alias has no bundled or published reader. | 2026-10-01 |
|
||||
| `agent-harness-terminal-result-aliases` | Move harnesses to `terminal` and `visibleReplies`, then prove the legacy result fields are unread. | 2026-10-01 |
|
||||
| `official-plugin-export-aliases` | Move users of Google Meet testing, channel presentation, and Discord timeout exports to canonical APIs. | 2026-10-01 |
|
||||
| `memory-host-compatibility-aliases` | Use canonical memory tables and prepared runtime config everywhere. | 2026-10-01 |
|
||||
| `plugin-runtime-api-compat-aliases` | Move flat plugin registration/runtime calls to their namespaced or focused replacements. | 2026-10-01 |
|
||||
| `plugin-provider-manifest-compat-aliases` | Move kind/setup/catalog ownership to manifests and model-catalog registration. | 2026-10-01 |
|
||||
| `deprecated-session-store-beta5-api` | End the v2026.7.x whole-store upgrade window, including package-root aliases. | 2026-10-12 |
|
||||
|
||||
`pnpm plugins:boundary-report` reports `removal-pending` records separately
|
||||
from deprecated records. A due `removal-pending` record remains blocked until
|
||||
its reported migration condition is satisfied and its reader references are
|
||||
cleared; the existing `--fail-on-eligible-compat` gate continues to apply only
|
||||
to dated `deprecated` records. Reader references are surface-token matches for
|
||||
triage; use the published-artifact sweep before authorizing removal.
|
||||
|
||||
### WhatsApp inbound callback flat aliases
|
||||
|
||||
WhatsApp runtime callbacks deliver `WebInboundMessage`: the canonical
|
||||
|
||||
@@ -89,6 +89,22 @@ If a manifest field is still accepted, keep using it until docs and
|
||||
diagnostics say otherwise. New code should prefer the documented replacement;
|
||||
existing plugins should not break during ordinary minor releases.
|
||||
|
||||
The dated compatibility registry also tracks shipped annotations that do not
|
||||
belong to one legacy subpath. These records use 2026-10-01 as the earliest
|
||||
review date; removal still requires the reader condition in the final column.
|
||||
|
||||
| Compatibility code | Replacement | Removal condition |
|
||||
| ----------------------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| `plugin-sdk-broad-runtime-barrels` | Focused capability subpaths | No bundled or published imports of the seven enumerated broad barrels remain. |
|
||||
| `plugin-sdk-provider-owned-helper-shims` | Provider-local auth/model/replay/OAuth/stream APIs | Every enumerated helper is migrated in official providers and absent from published plugins. |
|
||||
| `message-presentation-legacy-bridges` | `MessagePresentation` and channel presentation renderers | Producers and official channel packages no longer emit or read legacy interactive replies. |
|
||||
| `plugin-sdk-focused-compat-aliases` | The focused replacement named by each `@deprecated` annotation | Every enumerated alias has zero bundled and published readers. |
|
||||
| `agent-harness-terminal-result-aliases` | `AgentHarnessAttemptResult.terminal` and `visibleReplies` | Harness plugins no longer read legacy terminal booleans or `sourceVisibleReplies`. |
|
||||
| `official-plugin-export-aliases` | Canonical Google Meet testing, presentation renderers, and host-owned Discord timeout behavior | Minimum supported official plugin packages no longer import the aliases. |
|
||||
| `memory-host-compatibility-aliases` | Canonical memory tables and prepared runtime config | Memory integrations no longer pass table overrides or call legacy `loadConfig`. |
|
||||
| `plugin-runtime-api-compat-aliases` | Namespaced plugin APIs and focused runtime methods | All enumerated flat API/runtime aliases have no readers. |
|
||||
| `plugin-provider-manifest-compat-aliases` | Manifest-owned kind/setup metadata and model catalog registration | Providers no longer publish runtime kind or legacy catalog hooks. |
|
||||
|
||||
### Published channel setup compatibility
|
||||
|
||||
Slack, Discord, Signal, and Microsoft Teams packages published through
|
||||
@@ -141,9 +157,10 @@ key at a time.
|
||||
3. Resolve each candidate's latest published version. Run `npm pack <package>@<version> --json --pack-destination <temp-dir>`, unpack it, and inspect shipped `dist` JavaScript and declarations for direct or destructured field reads. Download the ClawHub artifact when a package has no npm release.
|
||||
4. Record package, version, field or promotion key, and matching file. A field or key is deletable only when no published plugin artifact reads it. Keep the reader names in the code comments beside the retained field and key lists synchronized with the sweep.
|
||||
|
||||
This is a source/type compatibility record only. It has no runtime adapter or
|
||||
compatibility-registry entry because runtime setup input objects and setup
|
||||
behavior are unchanged.
|
||||
This is a source/type compatibility record only. The registry entry has
|
||||
`removeAfter: 2026-10-01`, but setup input runtime objects and behavior are
|
||||
unchanged. The date starts a review; each field remains until its published
|
||||
artifact reader count is zero.
|
||||
|
||||
Audit the current migration queue with `pnpm plugins:boundary-report`:
|
||||
|
||||
@@ -161,8 +178,10 @@ records normally have an explicit `removeAfter` date rather than a vague "next
|
||||
major release". A record whose owner has not approved a date leaves
|
||||
`removeAfter` absent, appears as `no-date`, and is never eligible for removal.
|
||||
The report groups deprecated records by date, counts local code/doc references,
|
||||
surfaces cross-owner reserved SDK imports, and summarizes the private
|
||||
memory-host SDK bridge. Reserved SDK subpaths must have tracked owner usage;
|
||||
lists `removal-pending` dates with their blockers and surface-token reader
|
||||
references, surfaces cross-owner reserved SDK imports, and summarizes the
|
||||
private memory-host SDK bridge. Those reader references are triage signals, not
|
||||
published-artifact proof. Reserved SDK subpaths must have tracked owner usage;
|
||||
unused reserved exports should be removed from the public SDK.
|
||||
|
||||
### Media legacy projection
|
||||
@@ -779,9 +798,9 @@ timeline for current status.
|
||||
|
||||
| Migrating surface | Replacement |
|
||||
| ----------------- | ----------- |
|
||||
| Deprecated `loadSessionStore(...)`, `updateSessionStore(...)`, and `resolveSessionStoreEntry(...)` | `getSessionEntry(...)`, `listSessionEntries(...)`, and row-level session mutations. |
|
||||
| Deprecated `loadSessionStore(...)`, `updateSessionStore(...)`, and `resolveSessionStoreEntry(...)`, including package-root `loadSessionStore(...)` | `getSessionEntry(...)`, `listSessionEntries(...)`, and row-level session mutations. |
|
||||
| Deprecated `resolveSessionFilePath(...)` | Session identity (`sessionKey`, `sessionId`, and SDK runtime target helpers) plus Gateway methods that operate on the current session. |
|
||||
| Removed `saveSessionStore(...)` | Gateway-owned session runtime APIs; plugin code should request or mutate session state through documented runtime/context helpers instead of writing the active store file. |
|
||||
| Deprecated package-root `saveSessionStore(...)` and removed SDK file-store writes | Gateway-owned session runtime APIs; plugin code should request or mutate session state through documented runtime/context helpers instead of writing the active store file. |
|
||||
| Removed `resolveSessionTranscriptPathInDir(...)` and `resolveAndPersistSessionFile(...)` | Session identity and Gateway methods that operate on the current session. |
|
||||
| `readLatestAssistantTextFromSessionTranscript(...)` | Identity-backed transcript readers exposed by the current runtime context, or Gateway history/session methods when the plugin is outside the transcript owner path. |
|
||||
| `SessionTranscriptUpdate.sessionFile` | `SessionTranscriptUpdate.target` with `agentId`, `sessionKey`, and `sessionId`. |
|
||||
|
||||
@@ -265,7 +265,7 @@ function resolveStateDir(
|
||||
if (isFastTestRuntimeEnv(env) || fs.existsSync(nextDir)) {
|
||||
return nextDir;
|
||||
}
|
||||
// Existing legacy state remains authoritative until an explicit migration creates .openclaw.
|
||||
// Remove after 2026-10-01: drop legacy state-dir precedence once an explicit migration creates .openclaw.
|
||||
const existingLegacy = legacyStateDirs(effectiveHome).find((dir) => {
|
||||
try {
|
||||
return fs.existsSync(dir);
|
||||
|
||||
@@ -50,6 +50,21 @@ type CompatDebtRecord = {
|
||||
eligibleForRemoval: boolean;
|
||||
};
|
||||
|
||||
type RemovalPendingDebtRecord = {
|
||||
code: string;
|
||||
owner: string;
|
||||
status: "removal-pending";
|
||||
removeAfter?: string;
|
||||
blocker: string;
|
||||
readerFiles: string[];
|
||||
dueForReview: boolean;
|
||||
};
|
||||
|
||||
type RemovalPendingDebtSummary = Omit<RemovalPendingDebtRecord, "readerFiles"> & {
|
||||
readerCount: number;
|
||||
readerSample: string[];
|
||||
};
|
||||
|
||||
type WorkspaceTextFile = {
|
||||
file: string;
|
||||
relativeFile: string;
|
||||
@@ -71,6 +86,9 @@ type BoundaryReport = {
|
||||
deprecatedCount: number;
|
||||
eligibleForRemovalCount: number;
|
||||
records: CompatDebtRecord[];
|
||||
removalPendingCount: number;
|
||||
removalPendingDueCount: number;
|
||||
removalPending: RemovalPendingDebtRecord[];
|
||||
};
|
||||
pluginSdk: {
|
||||
entrypointCount: number;
|
||||
@@ -97,6 +115,9 @@ type BoundaryReportSummary = {
|
||||
eligibleForRemovalCount: number;
|
||||
deprecatedByOwner: Record<string, number>;
|
||||
eligibleForRemoval: Array<Pick<CompatDebtRecord, "code" | "owner" | "removeAfter">>;
|
||||
removalPendingCount: number;
|
||||
removalPendingDueCount: number;
|
||||
removalPending: RemovalPendingDebtSummary[];
|
||||
};
|
||||
pluginSdk: {
|
||||
entrypointCount: number;
|
||||
@@ -317,9 +338,8 @@ function resolveConsumerOwner(file: string): string | undefined {
|
||||
return /^extensions\/([^/]+)\//u.exec(file)?.[1];
|
||||
}
|
||||
|
||||
function extractCompatTokens(record: PluginCompatRecord): string[] {
|
||||
function extractCompatTokensFromValues(values: readonly (string | undefined)[]): string[] {
|
||||
const tokens = new Set<string>();
|
||||
const values = [record.code, record.replacement, ...record.surfaces, ...record.diagnostics];
|
||||
for (const value of values) {
|
||||
if (value === undefined) {
|
||||
continue;
|
||||
@@ -346,6 +366,19 @@ function extractCompatTokens(record: PluginCompatRecord): string[] {
|
||||
return [...tokens].toSorted();
|
||||
}
|
||||
|
||||
function extractCompatTokens(record: PluginCompatRecord): string[] {
|
||||
return extractCompatTokensFromValues([
|
||||
record.code,
|
||||
record.replacement,
|
||||
...record.surfaces,
|
||||
...record.diagnostics,
|
||||
]);
|
||||
}
|
||||
|
||||
function extractCompatSurfaceTokens(record: PluginCompatRecord): string[] {
|
||||
return extractCompatTokensFromValues(record.surfaces);
|
||||
}
|
||||
|
||||
function collectReferenceFiles(files: readonly WorkspaceTextFile[], tokens: readonly string[]) {
|
||||
const codeReferenceFiles = new Set<string>();
|
||||
const docReferenceFiles = new Set<string>();
|
||||
@@ -406,6 +439,34 @@ function collectCompatDebt(
|
||||
);
|
||||
}
|
||||
|
||||
function collectRemovalPendingDebt(
|
||||
files: readonly WorkspaceTextFile[],
|
||||
today = new Date(),
|
||||
): RemovalPendingDebtRecord[] {
|
||||
return listPluginCompatRecords()
|
||||
.filter((record) => record.status === "removal-pending")
|
||||
.map((record) => {
|
||||
const references = collectReferenceFiles(files, extractCompatSurfaceTokens(record));
|
||||
return {
|
||||
code: record.code,
|
||||
owner: record.owner,
|
||||
status: "removal-pending" as const,
|
||||
removeAfter: record.removeAfter,
|
||||
blocker: record.replacement ?? "no removal blocker documented",
|
||||
readerFiles: references.codeReferenceFiles,
|
||||
dueForReview: record.removeAfter
|
||||
? new Date(`${record.removeAfter}T00:00:00Z`) <= today
|
||||
: false,
|
||||
};
|
||||
})
|
||||
.toSorted(
|
||||
(left, right) =>
|
||||
(left.removeAfter ?? "").localeCompare(right.removeAfter ?? "") ||
|
||||
left.owner.localeCompare(right.owner) ||
|
||||
left.code.localeCompare(right.code),
|
||||
);
|
||||
}
|
||||
|
||||
function collectReservedSdkImports(files: readonly WorkspaceTextFile[]): ReservedSdkImport[] {
|
||||
const reserved = new Set<string>(reservedBundledPluginSdkEntrypoints);
|
||||
const pluginIds = collectBundledPluginIds();
|
||||
@@ -504,6 +565,13 @@ function buildSummary(report: BoundaryReport, owner?: string): BoundaryReportSum
|
||||
eligibleForRemovalCount: report.compat.eligibleForRemovalCount,
|
||||
deprecatedByOwner: countByOwner(report.compat.records),
|
||||
eligibleForRemoval,
|
||||
removalPendingCount: report.compat.removalPendingCount,
|
||||
removalPendingDueCount: report.compat.removalPendingDueCount,
|
||||
removalPending: report.compat.removalPending.map(({ readerFiles, ...record }) => ({
|
||||
...record,
|
||||
readerCount: readerFiles.length,
|
||||
readerSample: readerFiles.slice(0, 5),
|
||||
})),
|
||||
},
|
||||
pluginSdk: {
|
||||
entrypointCount: report.pluginSdk.entrypointCount,
|
||||
@@ -534,6 +602,9 @@ function buildReport(options: Partial<Pick<CliOptions, "owner" | "summary">> = {
|
||||
const compatRecords = collectCompatDebt(files, new Date(), {
|
||||
includeReferenceFiles: !options.summary,
|
||||
}).filter((record) => matchesOwner(options.owner, record.owner));
|
||||
const removalPending = collectRemovalPendingDebt(files).filter((record) =>
|
||||
matchesOwner(options.owner, record.owner),
|
||||
);
|
||||
const reservedImports = collectReservedSdkImports(files).filter(
|
||||
(entry) =>
|
||||
matchesOwner(options.owner, entry.owner) || matchesOwner(options.owner, entry.consumerOwner),
|
||||
@@ -552,6 +623,9 @@ function buildReport(options: Partial<Pick<CliOptions, "owner" | "summary">> = {
|
||||
deprecatedCount: compatRecords.length,
|
||||
eligibleForRemovalCount: compatRecords.filter((record) => record.eligibleForRemoval).length,
|
||||
records: compatRecords,
|
||||
removalPendingCount: removalPending.length,
|
||||
removalPendingDueCount: removalPending.filter((record) => record.dueForReview).length,
|
||||
removalPending,
|
||||
},
|
||||
pluginSdk: {
|
||||
entrypointCount: pluginSdkEntrypoints.length,
|
||||
@@ -573,8 +647,13 @@ function renderSummaryText(summary: BoundaryReportSummary): string {
|
||||
lines.push(`Plugin Boundary Report${summary.owner ? ` (${summary.owner})` : ""}`);
|
||||
lines.push("");
|
||||
lines.push(
|
||||
`compat deprecated=${summary.compat.deprecatedCount} eligibleForRemoval=${summary.compat.eligibleForRemovalCount}`,
|
||||
`compat deprecated=${summary.compat.deprecatedCount} eligibleForRemoval=${summary.compat.eligibleForRemovalCount} removalPending=${summary.compat.removalPendingCount} removalPendingDue=${summary.compat.removalPendingDueCount}`,
|
||||
);
|
||||
for (const record of summary.compat.removalPending) {
|
||||
lines.push(
|
||||
` removal-pending ${record.removeAfter ?? "no-date"} ${record.code} due=${record.dueForReview} blocker=${record.blocker} readerRefs=${record.readerCount} readers=${record.readerSample.join(",") || "none"}`,
|
||||
);
|
||||
}
|
||||
lines.push(
|
||||
`plugin-sdk entrypoints=${summary.pluginSdk.entrypointCount} reserved=${summary.pluginSdk.reservedCount}`,
|
||||
);
|
||||
@@ -598,13 +677,21 @@ function renderText(report: BoundaryReport, owner?: string): string {
|
||||
lines.push(`Plugin Boundary Report${owner ? ` (${owner})` : ""}`);
|
||||
lines.push("");
|
||||
lines.push(
|
||||
`compat deprecated=${report.compat.deprecatedCount} eligibleForRemoval=${report.compat.eligibleForRemovalCount}`,
|
||||
`compat deprecated=${report.compat.deprecatedCount} eligibleForRemoval=${report.compat.eligibleForRemovalCount} removalPending=${report.compat.removalPendingCount} removalPendingDue=${report.compat.removalPendingDueCount}`,
|
||||
);
|
||||
for (const record of report.compat.records) {
|
||||
lines.push(
|
||||
` ${record.removeAfter ?? "no-date"} ${record.code} owner=${record.owner} codeRefs=${record.codeReferenceFiles.length} docRefs=${record.docReferenceFiles.length}`,
|
||||
);
|
||||
}
|
||||
for (const record of report.compat.removalPending) {
|
||||
lines.push(
|
||||
` removal-pending ${record.removeAfter ?? "no-date"} ${record.code} due=${record.dueForReview} blocker=${record.blocker} readerRefs=${record.readerFiles.length}`,
|
||||
);
|
||||
for (const reader of record.readerFiles) {
|
||||
lines.push(` reader ${reader}`);
|
||||
}
|
||||
}
|
||||
lines.push("");
|
||||
lines.push(
|
||||
`plugin-sdk entrypoints=${report.pluginSdk.entrypointCount} reserved=${report.pluginSdk.reservedCount} supportedBundledFacade=${report.pluginSdk.supportedBundledFacadeCount} publicPluginOwned=${report.pluginSdk.publicPluginOwnedCount}`,
|
||||
|
||||
@@ -340,6 +340,7 @@ function migrateRegisteredDatabase(params: {
|
||||
`${params.pathname} metadata schema version ${metadata.schemaVersion ?? "invalid"} does not match ${userVersion}`,
|
||||
);
|
||||
}
|
||||
// Remove after 2026-10-12: drop the v15-to-v16 media cutover once schema 16 is the support floor.
|
||||
if (userVersion === PREVIOUS_MEDIA_SCHEMA_VERSION) {
|
||||
repairCanonicalSqliteIndexes(database, params.pathname, OPENCLAW_AGENT_SCHEMA_SQL, {
|
||||
validateAfterRepair: () =>
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
import type { PluginCompatRecord } from "./types.js";
|
||||
|
||||
const MARKING_DATE = "2026-07-25";
|
||||
const DEFAULT_REMOVE_AFTER = "2026-10-01";
|
||||
|
||||
/** Dated metadata for shipped deprecated surfaces that previously had annotations only. */
|
||||
export const DEPRECATION_MARKING_COMPAT_RECORDS = [
|
||||
{
|
||||
code: "plugin-sdk-channel-setup-input-fields",
|
||||
status: "deprecated",
|
||||
owner: "channel",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "plugin-local setup input intersections that declare each owning channel field",
|
||||
docsPath: "/plugins/sdk-migration#published-channel-setup-compatibility",
|
||||
surfaces: [
|
||||
"ChannelSetupInput.privateKey",
|
||||
"ChannelSetupInput.secret",
|
||||
"ChannelSetupInput.botToken",
|
||||
"ChannelSetupInput.appToken",
|
||||
"ChannelSetupInput.signingSecret",
|
||||
"ChannelSetupInput.mode",
|
||||
"ChannelSetupInput.cliPath",
|
||||
"ChannelSetupInput.authDir",
|
||||
"ChannelSetupInput.httpUrl",
|
||||
"ChannelSetupInput.httpPort",
|
||||
"ChannelSetupInput.webhookPath",
|
||||
"ChannelSetupInput.webhookUrl",
|
||||
"ChannelSetupInput.userId",
|
||||
"ChannelSetupInput.accessToken",
|
||||
"ChannelSetupInput.password",
|
||||
"ChannelSetupInput.deviceName",
|
||||
"ChannelSetupInput.url",
|
||||
"ChannelSetupInput.baseUrl",
|
||||
"ChannelSetupInput.code",
|
||||
"ChannelSetupInput.groupChannels",
|
||||
"ChannelSetupInput.dmAllowlist",
|
||||
"ChannelSetupInput.autoDiscoverChannels",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on the reader-backed ChannelSetupInput compatibility tier",
|
||||
"published-plugin artifact reader sweep required before field removal",
|
||||
],
|
||||
tests: ["src/plugin-sdk/channel-setup.test.ts", "src/plugins/compat/registry.test.ts"],
|
||||
releaseNote:
|
||||
"ChannelSetupInput keeps its reader-backed channel fields through the dated migration window while plugins move them into plugin-local input types.",
|
||||
},
|
||||
{
|
||||
code: "plugin-sdk-broad-runtime-barrels",
|
||||
status: "deprecated",
|
||||
owner: "sdk",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "focused plugin SDK subpaths for each runtime capability",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"openclaw/plugin-sdk/agent-runtime",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog params.useCache",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog params.cacheOnly",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog params.metadataSnapshot",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog",
|
||||
"openclaw/plugin-sdk/cli-runtime",
|
||||
"openclaw/plugin-sdk/conversation-runtime",
|
||||
"openclaw/plugin-sdk/hook-runtime",
|
||||
"openclaw/plugin-sdk/media-runtime",
|
||||
"openclaw/plugin-sdk/media-runtime buildAgentMediaPayload",
|
||||
"openclaw/plugin-sdk/plugin-runtime",
|
||||
"openclaw/plugin-sdk/security-runtime",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on broad plugin SDK barrels",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/plugins/contracts/plugin-sdk-subpaths.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Broad agent, CLI, conversation, hook, media, plugin, and security runtime barrels remain available while bundled and external plugins migrate to focused subpaths.",
|
||||
},
|
||||
{
|
||||
code: "plugin-sdk-provider-owned-helper-shims",
|
||||
status: "deprecated",
|
||||
owner: "provider",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "provider-local auth, model, replay, OAuth, and stream helper APIs",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"openclaw/plugin-sdk/provider-stream GOOGLE_THINKING_STREAM_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream KILOCODE_THINKING_STREAM_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream MOONSHOT_THINKING_STREAM_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream MINIMAX_FAST_MODE_STREAM_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream OPENAI_RESPONSES_STREAM_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream OPENROUTER_THINKING_STREAM_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream TOOL_STREAM_DEFAULT_ON_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-stream-shared defaultToolStreamExtraParams",
|
||||
"openclaw/plugin-sdk/provider-stream-shared stripTrailingAnthropicAssistantPrefillWhenThinking",
|
||||
"openclaw/plugin-sdk/provider-stream-shared createAnthropicThinkingPrefillPayloadWrapper",
|
||||
"openclaw/plugin-sdk/provider-stream-shared OpenAICompatibleThinkingLevel",
|
||||
"openclaw/plugin-sdk/provider-stream-shared isOpenAICompatibleThinkingEnabled",
|
||||
"openclaw/plugin-sdk/provider-stream-shared DeepSeekV4ThinkingLevel",
|
||||
"openclaw/plugin-sdk/provider-stream-shared DeepSeekV4ReasoningEffort",
|
||||
"openclaw/plugin-sdk/provider-stream-shared createDeepSeekV4OpenAICompatibleThinkingWrapper",
|
||||
"openclaw/plugin-sdk/provider-stream-shared createThinkingOnlyFinalTextWrapper",
|
||||
"openclaw/plugin-sdk/provider-stream-shared createGoogleThinkingPayloadWrapper",
|
||||
"openclaw/plugin-sdk/provider-stream-shared createGoogleThinkingStreamWrapper",
|
||||
"openclaw/plugin-sdk/provider-model-shared isProxyReasoningUnsupportedModelHint",
|
||||
"openclaw/plugin-sdk/provider-model-shared OPENAI_COMPATIBLE_REPLAY_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-model-shared ANTHROPIC_BY_MODEL_REPLAY_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-model-shared NATIVE_ANTHROPIC_REPLAY_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-model-shared PASSTHROUGH_GEMINI_REPLAY_HOOKS",
|
||||
"openclaw/plugin-sdk/provider-auth DEFAULT_COPILOT_API_BASE_URL",
|
||||
"openclaw/plugin-sdk/provider-auth deriveCopilotApiBaseUrlFromToken",
|
||||
"openclaw/plugin-sdk/provider-auth resolveCopilotApiToken",
|
||||
"openclaw/plugin-sdk/provider-auth-login.runtime loginChutes",
|
||||
"openclaw/plugin-sdk/provider-auth-login.runtime loginOpenAICodexOAuth",
|
||||
"openclaw/plugin-sdk/provider-auth-login.runtime githubCopilotLoginCommand",
|
||||
"openclaw/plugin-sdk/provider-auth-copilot-cache CachedCopilotToken",
|
||||
"openclaw/plugin-sdk/github-copilot-login githubCopilotLoginCommand",
|
||||
"openclaw/plugin-sdk/oauth-utils toFormUrlEncoded",
|
||||
"openclaw/plugin-sdk/oauth-utils generatePkceVerifierChallenge",
|
||||
"openclaw/plugin-sdk/provider-oauth-runtime OAuthProvider",
|
||||
"openclaw/plugin-sdk/provider-oauth-runtime OAuthProviderInfo",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations naming provider-local replacements",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/plugins/contracts/plugin-sdk-subpaths.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Provider-specific auth, model, replay, OAuth, and stream shortcuts remain as deprecated SDK shims while providers move to their local APIs.",
|
||||
},
|
||||
{
|
||||
code: "message-presentation-legacy-bridges",
|
||||
status: "deprecated",
|
||||
owner: "channel",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "MessagePresentation values and channel presentation renderers",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"InteractiveReplyButton.value",
|
||||
"InteractiveReplyButton.url",
|
||||
"InteractiveReplyButton.webApp",
|
||||
"InteractiveReplyButton.web_app",
|
||||
"InteractiveReplyOption.value",
|
||||
"InteractiveReplyButton",
|
||||
"InteractiveReplyOption",
|
||||
"InteractiveReplyBlock",
|
||||
"InteractiveReply",
|
||||
"normalizeInteractiveReply",
|
||||
"hasInteractiveReplyBlocks",
|
||||
"presentationToInteractiveReply",
|
||||
"presentationToInteractiveControlsReply",
|
||||
"interactiveReplyToPresentation",
|
||||
"resolveInteractiveTextFallback",
|
||||
"src/auto-reply ReplyPayload.interactive",
|
||||
"openclaw/plugin-sdk/reply-payload ReplyPayload.interactive",
|
||||
"reduceInteractiveReply",
|
||||
"@openclaw/discord buildDiscordInteractiveComponents",
|
||||
"@openclaw/slack isSlackInteractiveRepliesEnabled",
|
||||
"@openclaw/slack compileSlackInteractiveReplies",
|
||||
"@openclaw/slack parseSlackOptionsLine",
|
||||
"@openclaw/slack buildSlackInteractiveBlocks",
|
||||
"@openclaw/telegram buildTelegramInteractiveButtons",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations naming MessagePresentation replacements",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/interactive/payload.test.ts",
|
||||
"src/plugin-sdk/reply-payload.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Legacy interactive reply values and channel-specific rendering bridges remain available while producers migrate to MessagePresentation.",
|
||||
},
|
||||
{
|
||||
code: "plugin-sdk-focused-compat-aliases",
|
||||
status: "deprecated",
|
||||
owner: "sdk",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "the focused replacement named by each TypeScript @deprecated annotation",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"openclaw/plugin-sdk/acp-runtime __testing",
|
||||
"openclaw/plugin-sdk/approval-reaction-runtime",
|
||||
"openclaw/plugin-sdk/channel-inbound BuildChannelTurnContextParams",
|
||||
"openclaw/plugin-sdk/channel-inbound BuiltChannelTurnContext",
|
||||
"openclaw/plugin-sdk/channel-inbound buildChannelTurnContext",
|
||||
"openclaw/plugin-sdk/channel-inbound finalizeChannelInboundContext",
|
||||
"openclaw/plugin-sdk/channel-inbound filterChannelTurnSupplementalContext",
|
||||
"openclaw/plugin-sdk/channel-send-result ChannelSendRawResult",
|
||||
"openclaw/plugin-sdk/command-auth",
|
||||
"openclaw/plugin-sdk/command-auth ResolveSenderCommandAuthorizationParams",
|
||||
"openclaw/plugin-sdk/command-auth resolveCommandAuthorizedFromAuthorizers",
|
||||
"openclaw/plugin-sdk/command-auth CommandAuthorizationRuntime",
|
||||
"openclaw/plugin-sdk/command-auth ResolveSenderCommandAuthorizationWithRuntimeParams",
|
||||
"openclaw/plugin-sdk/command-auth resolveDirectDmAuthorizationOutcome",
|
||||
"openclaw/plugin-sdk/command-auth resolveSenderCommandAuthorizationWithRuntime",
|
||||
"openclaw/plugin-sdk/command-auth resolveSenderCommandAuthorization",
|
||||
"openclaw/plugin-sdk/keyed-async-queue KeyedAsyncQueue.getTailMapForTesting",
|
||||
"openclaw/plugin-sdk/persistent-dedupe PersistentDedupeLegacyPathOptions.lockOptions",
|
||||
"openclaw/plugin-sdk/retry-runtime createTelegramRetryRunner",
|
||||
"openclaw/plugin-sdk/ssrf-policy SsrfPolicyOptions.allowPrivateNetwork",
|
||||
"openclaw/plugin-sdk/ssrf-policy ssrfPolicyFromAllowPrivateNetwork",
|
||||
"openclaw/plugin-sdk/tts-runtime TtsSynthesisStreamResult",
|
||||
"openclaw/plugin-sdk/tts-runtime TtsRuntimeFacade._test",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations naming focused replacements",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/plugin-sdk/channel-inbound.test.ts",
|
||||
"src/plugin-sdk/command-auth.test.ts",
|
||||
"src/plugin-sdk/ssrf-policy.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Focused SDK compatibility aliases remain available through a dated window while callers adopt their annotated replacements.",
|
||||
},
|
||||
{
|
||||
code: "agent-harness-terminal-result-aliases",
|
||||
status: "deprecated",
|
||||
owner: "agent-runtime",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement:
|
||||
"AgentHarnessAttemptResult.terminal and AgentHarnessDeliveryDefaults.visibleReplies",
|
||||
docsPath: "/plugins/sdk-agent-harness",
|
||||
surfaces: [
|
||||
"AgentHarnessAttemptResult.aborted",
|
||||
"AgentHarnessAttemptResult.externalAbort",
|
||||
"AgentHarnessAttemptResult.timedOut",
|
||||
"AgentHarnessAttemptResult.idleTimedOut",
|
||||
"AgentHarnessAttemptResult.timedOutDuringCompaction",
|
||||
"AgentHarnessAttemptResult.timedOutDuringToolExecution",
|
||||
"AgentHarnessAttemptResult.timedOutByRunBudget",
|
||||
"AgentHarnessAttemptResult.promptError",
|
||||
"AgentHarnessAttemptResult.promptErrorSource",
|
||||
"AgentHarnessDeliveryDefaults.sourceVisibleReplies",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on agent harness result and delivery defaults",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/agents/harness/settled-turn-finalization-result.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Agent harness result booleans and sourceVisibleReplies remain available while harnesses migrate to terminal outcomes and visibleReplies.",
|
||||
},
|
||||
{
|
||||
code: "official-plugin-export-aliases",
|
||||
status: "deprecated",
|
||||
owner: "channel",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement:
|
||||
"the canonical testing export, MessagePresentation renderers, and host-owned timeout/runtime behavior",
|
||||
docsPath: "/plugins/compatibility#current-compatibility-areas",
|
||||
surfaces: [
|
||||
"@openclaw/google-meet __testing",
|
||||
"@openclaw/discord buildDiscordInteractiveComponents",
|
||||
"@openclaw/discord normalizeDiscordListenerTimeoutMs",
|
||||
"@openclaw/discord normalizeDiscordInboundWorkerTimeoutMs",
|
||||
"@openclaw/discord isAbortError",
|
||||
"@openclaw/discord runDiscordTaskWithTimeout",
|
||||
"@openclaw/slack buildSlackInteractiveBlocks",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on published official-plugin exports",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
// Owning discord/slack suites live under extensions/*/src; the core import
|
||||
// guardrail forbids that path shape in core string literals, so cite the
|
||||
// package-root and registry tests here.
|
||||
tests: ["extensions/google-meet/index.test.ts", "src/plugins/compat/registry.test.ts"],
|
||||
releaseNote:
|
||||
"Published Google Meet testing, channel presentation, and Discord timeout aliases remain available while consumers move to their canonical exports and host-owned behavior.",
|
||||
},
|
||||
{
|
||||
code: "memory-host-compatibility-aliases",
|
||||
status: "deprecated",
|
||||
owner: "sdk",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "canonical memory cache/FTS tables and getRuntimeConfig or caller-provided config",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"@openclaw/memory-host-sdk ensureMemoryIndexSchema.embeddingCacheTable",
|
||||
"@openclaw/memory-host-sdk ensureMemoryIndexSchema.ftsTable",
|
||||
"@openclaw/memory-host-sdk/runtime-core loadConfig",
|
||||
"@openclaw/memory-host-sdk/host/openclaw-runtime loadConfig",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on memory-host SDK compatibility fields",
|
||||
"plugin boundary report memory-host SDK summary",
|
||||
],
|
||||
tests: [
|
||||
"packages/memory-host-sdk/src/host/memory-schema.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Memory-host cache-table overrides and runtime config reload aliases remain available while callers migrate to canonical tables and prepared config.",
|
||||
},
|
||||
{
|
||||
code: "plugin-runtime-api-compat-aliases",
|
||||
status: "deprecated",
|
||||
owner: "plugin-execution",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "the namespaced plugin API and focused runtime methods named per surface",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"OpenClawPluginApi.registerSessionExtension",
|
||||
"OpenClawPluginApi.enqueueNextTurnInjection",
|
||||
"OpenClawPluginApi.registerControlUiDescriptor",
|
||||
"OpenClawPluginApi.registerRuntimeLifecycle",
|
||||
"OpenClawPluginApi.registerAgentEventSubscription",
|
||||
"OpenClawPluginApi.emitAgentEvent",
|
||||
"OpenClawPluginApi.setRunContext",
|
||||
"OpenClawPluginApi.getRunContext",
|
||||
"OpenClawPluginApi.clearRunContext",
|
||||
"OpenClawPluginApi.registerSessionSchedulerJob",
|
||||
"OpenClawPluginApi.registerSessionAction",
|
||||
"OpenClawPluginApi.sendSessionAttachment",
|
||||
"OpenClawPluginApi.scheduleSessionTurn",
|
||||
"OpenClawPluginApi.unscheduleSessionTurnsByTag",
|
||||
"PluginHookContext.senderExternalId",
|
||||
"PluginAttachmentChannelHints.telegram",
|
||||
"PluginAttachmentChannelHints.slack",
|
||||
"AgentPromptSurfaceKind pi_main",
|
||||
"PluginRuntime.channel.reply.createReplyDispatcherWithTyping",
|
||||
"PluginRuntime.channel.reply.resolveHumanDelayConfig",
|
||||
"PluginRuntime.channel.reply.dispatchReplyFromConfig",
|
||||
"PluginRuntime.channel.reply.finalizeInboundContext",
|
||||
"PluginRuntime.channel.media.fetchRemoteMedia",
|
||||
"PluginRuntime.channel.session.resolveStorePath",
|
||||
"PluginRuntime.channel.session.recordInboundSession",
|
||||
"PluginRuntime.channel.inbound.runPreparedReply",
|
||||
"PluginRuntime.system.requestHeartbeatNow",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on plugin API and runtime aliases",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/plugins/captured-registration.test.ts",
|
||||
"src/plugins/runtime/index.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Flat plugin registration and broad runtime aliases remain available while plugins migrate to namespaced APIs and focused runtime methods.",
|
||||
},
|
||||
{
|
||||
code: "plugin-provider-manifest-compat-aliases",
|
||||
status: "deprecated",
|
||||
owner: "provider",
|
||||
introduced: MARKING_DATE,
|
||||
deprecated: MARKING_DATE,
|
||||
warningStarts: MARKING_DATE,
|
||||
removeAfter: DEFAULT_REMOVE_AFTER,
|
||||
replacement: "manifest-owned plugin kind/setup metadata and model catalog registration",
|
||||
docsPath: "/plugins/sdk-migration#compatibility-policy",
|
||||
surfaces: [
|
||||
"DefinePluginEntryOptions.kind",
|
||||
"SingleProviderPluginOptions.kind",
|
||||
"OpenClawPluginDefinition.kind",
|
||||
"PluginPackageChannel.cliAddOptions",
|
||||
"ProviderPlugin.catalog",
|
||||
"ProviderPlugin.staticCatalog",
|
||||
"ProviderPlugin.suppressBuiltInModel",
|
||||
"ProviderPlugin.augmentModelCatalog",
|
||||
"ProviderBuiltInModelSuppressionContext",
|
||||
],
|
||||
diagnostics: [
|
||||
"TypeScript @deprecated annotations on plugin manifest and provider catalog aliases",
|
||||
"plugin boundary report compatibility inventory",
|
||||
],
|
||||
tests: [
|
||||
"src/plugins/contracts/package-manifest.contract.test.ts",
|
||||
"src/plugins/contracts/provider-catalog-deprecation.contract.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"Runtime plugin kind/setup metadata and provider catalog hooks remain available while plugins migrate ownership into manifests and catalog registrations.",
|
||||
},
|
||||
] as const satisfies readonly PluginCompatRecord[];
|
||||
@@ -22,6 +22,30 @@ const deprecatedTargetParserCompatFiles = new Set([
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
]);
|
||||
const removalDatePendingCompatCodes = new Set<string>();
|
||||
const deprecationMarkingCodes = [
|
||||
"plugin-sdk-channel-setup-input-fields",
|
||||
"plugin-sdk-broad-runtime-barrels",
|
||||
"plugin-sdk-provider-owned-helper-shims",
|
||||
"message-presentation-legacy-bridges",
|
||||
"plugin-sdk-focused-compat-aliases",
|
||||
"agent-harness-terminal-result-aliases",
|
||||
"official-plugin-export-aliases",
|
||||
"memory-host-compatibility-aliases",
|
||||
"plugin-runtime-api-compat-aliases",
|
||||
"plugin-provider-manifest-compat-aliases",
|
||||
] as const;
|
||||
const deprecationMarkingSurfaceCounts: Record<(typeof deprecationMarkingCodes)[number], number> = {
|
||||
"plugin-sdk-channel-setup-input-fields": 22,
|
||||
"plugin-sdk-broad-runtime-barrels": 12,
|
||||
"plugin-sdk-provider-owned-helper-shims": 35,
|
||||
"message-presentation-legacy-bridges": 24,
|
||||
"plugin-sdk-focused-compat-aliases": 23,
|
||||
"agent-harness-terminal-result-aliases": 10,
|
||||
"official-plugin-export-aliases": 7,
|
||||
"memory-host-compatibility-aliases": 4,
|
||||
"plugin-runtime-api-compat-aliases": 27,
|
||||
"plugin-provider-manifest-compat-aliases": 9,
|
||||
};
|
||||
function expectNonEmptyStringList(values: readonly string[], label: string) {
|
||||
expect(values, label).toEqual([expect.stringMatching(/\S/u), ...values.slice(1)]);
|
||||
for (const value of values) {
|
||||
@@ -88,6 +112,45 @@ describe("plugin compatibility registry", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("tracks the deprecation-marking families through the approved window", () => {
|
||||
const records = new Map(listPluginCompatRecords().map((record) => [record.code, record]));
|
||||
|
||||
expect(deprecationMarkingCodes.map((code) => records.get(code)?.code)).toEqual(
|
||||
deprecationMarkingCodes,
|
||||
);
|
||||
for (const code of deprecationMarkingCodes) {
|
||||
expect(records.get(code)).toMatchObject({
|
||||
status: "deprecated",
|
||||
deprecated: "2026-07-25",
|
||||
warningStarts: "2026-07-25",
|
||||
removeAfter: "2026-10-01",
|
||||
});
|
||||
expect(records.get(code)?.surfaces, code).toHaveLength(deprecationMarkingSurfaceCounts[code]);
|
||||
}
|
||||
expect(records.get("plugin-sdk-broad-runtime-barrels")?.surfaces).toEqual(
|
||||
expect.arrayContaining([
|
||||
"openclaw/plugin-sdk/agent-runtime",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog params.useCache",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog params.cacheOnly",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog params.metadataSnapshot",
|
||||
"openclaw/plugin-sdk/agent-runtime loadModelCatalog",
|
||||
"openclaw/plugin-sdk/cli-runtime",
|
||||
"openclaw/plugin-sdk/conversation-runtime",
|
||||
"openclaw/plugin-sdk/hook-runtime",
|
||||
"openclaw/plugin-sdk/media-runtime",
|
||||
"openclaw/plugin-sdk/media-runtime buildAgentMediaPayload",
|
||||
"openclaw/plugin-sdk/plugin-runtime",
|
||||
"openclaw/plugin-sdk/security-runtime",
|
||||
]),
|
||||
);
|
||||
expect(records.get("deprecated-session-store-beta5-api")?.surfaces).toEqual(
|
||||
expect.arrayContaining([
|
||||
"openclaw package root loadSessionStore",
|
||||
"openclaw package root saveSessionStore",
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps deprecated explicit target parser calls inside compatibility shims", () => {
|
||||
expect(deprecatedTargetParserOffenders).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { DEPRECATION_MARKING_COMPAT_RECORDS } from "./deprecation-marking.js";
|
||||
import { MEDIA_LEGACY_PROJECTION_COMPAT_RECORD } from "./media-legacy-projection.js";
|
||||
// Plugin compatibility registry exposes known plugin compatibility metadata to doctor/update flows.
|
||||
import type { PluginCompatRecord } from "./types.js";
|
||||
@@ -194,6 +195,7 @@ const BUNDLED_ONLY_PUBLIC_PLUGIN_SDK_SUBPATH_RECORDS = BUNDLED_ONLY_PUBLIC_PLUGI
|
||||
const PLUGIN_COMPAT_RECORDS = [
|
||||
...DEPRECATED_PLUGIN_SDK_SUBPATH_RECORDS,
|
||||
...BUNDLED_ONLY_PUBLIC_PLUGIN_SDK_SUBPATH_RECORDS,
|
||||
...DEPRECATION_MARKING_COMPAT_RECORDS,
|
||||
MEDIA_LEGACY_PROJECTION_COMPAT_RECORD,
|
||||
{
|
||||
code: "removed-global-api-provider-publication",
|
||||
@@ -302,11 +304,17 @@ const PLUGIN_COMPAT_RECORDS = [
|
||||
"openclaw/plugin-sdk/session-store-runtime updateSessionStore",
|
||||
"openclaw/plugin-sdk/session-store-runtime resolveSessionFilePath",
|
||||
"openclaw/plugin-sdk/session-store-runtime resolveSessionStoreEntry",
|
||||
"openclaw package root loadSessionStore",
|
||||
"openclaw package root saveSessionStore",
|
||||
],
|
||||
diagnostics: ["plugin SDK deprecation"],
|
||||
tests: ["src/plugin-sdk/session-store-runtime.test.ts", "src/plugins/compat/registry.test.ts"],
|
||||
tests: [
|
||||
"src/plugin-sdk/session-store-runtime.test.ts",
|
||||
"src/index.test.ts",
|
||||
"src/plugins/compat/registry.test.ts",
|
||||
],
|
||||
releaseNote:
|
||||
"The beta.5 session-store import set remains available for official plugins released with v2026.7.1-beta.5 while they migrate to row-level session access.",
|
||||
"The beta.5 session-store import set and package-root whole-store aliases remain available while official plugins and package consumers migrate to row-level session access.",
|
||||
},
|
||||
{
|
||||
code: "removed-session-transcript-file-api",
|
||||
|
||||
@@ -92,6 +92,7 @@ function migrateOpenClawAgentSchema(db: DatabaseSync): void {
|
||||
if (userVersion >= OPENCLAW_AGENT_SCHEMA_VERSION) {
|
||||
return;
|
||||
}
|
||||
// Remove after 2026-10-01: drop the v1-v6 ladder once the minimum supported agent schema is 7.
|
||||
if (userVersion < 7) {
|
||||
db.exec("DROP INDEX IF EXISTS idx_agent_sessions_status;");
|
||||
migrateSessionEntryStatusProjection(db, (entryJson) => {
|
||||
@@ -225,6 +226,7 @@ function migrateOpenClawAgentSchema(db: DatabaseSync): void {
|
||||
|
||||
/** Backfill one generation token without copying or rewriting transcript rows. */
|
||||
function migrateSessionTranscriptGenerations(db: DatabaseSync, previousVersion: number): void {
|
||||
// Remove after 2026-10-01: drop the generation backfill once the minimum supported agent schema is 13.
|
||||
if (previousVersion >= 13) {
|
||||
return;
|
||||
}
|
||||
@@ -548,6 +550,7 @@ function ensureAgentSchema(
|
||||
migrateOpenClawAgentSchema(db);
|
||||
migrateConversationDeliveryTargetColumn(db);
|
||||
backfillOpenClawAgentSchema(db, previousVersion);
|
||||
// Remove after 2026-10-01: drop the pre-v11 conversation backfill once schema 11 is the support floor.
|
||||
if (previousVersion < 11) {
|
||||
backfillSessionConversations(db);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,18 @@ describe("plugin-boundary-report", () => {
|
||||
|
||||
it("emits compact CI-safe summary JSON", () => {
|
||||
const summary = JSON.parse(summaryResult.stdout) as {
|
||||
compat?: {
|
||||
removalPendingCount?: unknown;
|
||||
removalPendingDueCount?: unknown;
|
||||
removalPending?: Array<{
|
||||
code?: unknown;
|
||||
removeAfter?: unknown;
|
||||
blocker?: unknown;
|
||||
readerCount?: unknown;
|
||||
readerSample?: unknown;
|
||||
dueForReview?: unknown;
|
||||
}>;
|
||||
};
|
||||
pluginSdk?: {
|
||||
crossOwnerReservedImportCount?: unknown;
|
||||
unusedReservedCount?: unknown;
|
||||
@@ -42,6 +54,23 @@ describe("plugin-boundary-report", () => {
|
||||
|
||||
expect(summaryResult.exitCode).toBe(0);
|
||||
expect(summaryResult.stderr).toBe("");
|
||||
expect(summary.compat?.removalPendingCount).toBe(5);
|
||||
expect(summary.compat?.removalPendingDueCount).toEqual(expect.any(Number));
|
||||
expect(summary.compat?.removalPending?.map((record) => record.code)).toEqual([
|
||||
"agent-harness-sdk-alias",
|
||||
"plugin-sdk-media-understanding-public-demotion",
|
||||
"plugin-sdk-memory-host-core-public-demotion",
|
||||
"plugin-sdk-plugin-config-runtime-public-demotion",
|
||||
"plugin-sdk-tool-plugin-public-demotion",
|
||||
]);
|
||||
for (const record of summary.compat?.removalPending ?? []) {
|
||||
expect(record.removeAfter).toMatch(/^\d{4}-\d{2}-\d{2}$/u);
|
||||
expect(record.blocker).toEqual(expect.stringMatching(/retain|replacement/iu));
|
||||
expect(record.readerCount).toEqual(expect.any(Number));
|
||||
expect(record.readerSample).toEqual(expect.arrayContaining([expect.any(String)]));
|
||||
expect((record.readerSample as unknown[]).length).toBeLessThanOrEqual(5);
|
||||
expect(record.dueForReview).toEqual(expect.any(Boolean));
|
||||
}
|
||||
const pluginSdk = requirePluginSdkSummary(summary);
|
||||
expect(pluginSdk.crossOwnerReservedImportCount).toBe(0);
|
||||
expect(pluginSdk.unusedReservedCount).toBe(0);
|
||||
@@ -49,4 +78,15 @@ describe("plugin-boundary-report", () => {
|
||||
summary.memoryHostSdk?.implementation,
|
||||
);
|
||||
});
|
||||
|
||||
it("renders removal-pending blockers and reader references without changing fail gates", () => {
|
||||
const result = createPluginBoundaryReport(["--summary"]);
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.stderr).toBe("");
|
||||
expect(result.stdout).toContain("removalPending=5");
|
||||
expect(result.stdout).toContain("removal-pending 2026-07-25 agent-harness-sdk-alias");
|
||||
expect(result.stdout).toMatch(/blocker=.*retain the public/iu);
|
||||
expect(result.stdout).toMatch(/readerRefs=\d+ readers=/u);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user