mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-06 23:55:12 +00:00
refactor(plugin-sdk): annotate dormant reserved subpaths
This commit is contained in:
@@ -96,8 +96,11 @@ compatibility records, cross-owner reserved SDK imports, or unused reserved SDK
|
||||
subpaths without a dormant classification. The report groups deprecated
|
||||
compatibility records by removal date, counts local code/docs references,
|
||||
surfaces cross-owner reserved SDK imports, classifies dormant reserved SDK
|
||||
subpaths, and summarizes the private memory-host SDK bridge so compatibility
|
||||
cleanup stays explicit instead of relying on ad hoc searches.
|
||||
subpaths with owner/replacement/remove-after metadata, and summarizes the
|
||||
private memory-host SDK bridge so compatibility cleanup stays explicit instead
|
||||
of relying on ad hoc searches. Dormant reserved SDK subpaths are package exports
|
||||
with no tracked repo imports; keep them until their recorded removal date unless
|
||||
a separate compatibility review proves the external import never shipped.
|
||||
|
||||
If a manifest field is still accepted, plugin authors can keep using it until
|
||||
the docs and diagnostics say otherwise. New code should prefer the documented
|
||||
|
||||
@@ -11,7 +11,9 @@ This page catalogs the commonly used subpaths grouped by purpose. The generated
|
||||
full list of 200+ subpaths lives in `scripts/lib/plugin-sdk-entrypoints.json`;
|
||||
reserved bundled-plugin helper subpaths appear there but are implementation
|
||||
detail unless a doc page explicitly promotes them. Maintainers can audit active
|
||||
and dormant reserved helper subpaths with `pnpm plugins:boundary-report:summary`.
|
||||
and dormant reserved helper subpaths with `pnpm plugins:boundary-report:summary`;
|
||||
the full JSON report includes dormant helper owner, replacement, and
|
||||
remove-after metadata.
|
||||
|
||||
For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview).
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
|
||||
import { join, relative, resolve } from "node:path";
|
||||
import {
|
||||
dormantReservedBundledPluginSdkEntrypoints,
|
||||
dormantReservedBundledPluginSdkEntrypointRecords,
|
||||
pluginSdkEntrypoints,
|
||||
publicPluginOwnedSdkEntrypoints,
|
||||
reservedBundledPluginSdkEntrypoints,
|
||||
supportedBundledFacadeSdkEntrypoints,
|
||||
} from "../src/plugin-sdk/entrypoints.ts";
|
||||
import type { DormantReservedBundledPluginSdkEntrypointRecord } from "../src/plugin-sdk/entrypoints.ts";
|
||||
import { PLUGIN_COMPAT_RECORDS } from "../src/plugins/compat/registry.ts";
|
||||
import type { PluginCompatRecord } from "../src/plugins/compat/types.ts";
|
||||
|
||||
@@ -75,7 +77,9 @@ type BoundaryReport = {
|
||||
crossOwnerReservedImports: ReservedSdkImport[];
|
||||
unusedReservedSubpaths: string[];
|
||||
dormantReservedSubpaths: string[];
|
||||
dormantReservedRecords: DormantReservedBundledPluginSdkEntrypointRecord[];
|
||||
unclassifiedUnusedReservedSubpaths: string[];
|
||||
dormantReservedEligibleForRemovalSubpaths: string[];
|
||||
};
|
||||
memoryHostSdk: {
|
||||
privatePackage: boolean;
|
||||
@@ -106,6 +110,8 @@ type BoundaryReportSummary = {
|
||||
dormantReservedCountInUnused: number;
|
||||
unclassifiedUnusedReservedCount: number;
|
||||
unclassifiedUnusedReservedSubpaths: string[];
|
||||
dormantReservedEligibleForRemovalCount: number;
|
||||
dormantReservedEligibleForRemovalSubpaths: string[];
|
||||
crossOwnerReservedImports: ReservedSdkImport[];
|
||||
};
|
||||
memoryHostSdk: {
|
||||
@@ -381,6 +387,10 @@ function resolveMemoryHostImplementation(
|
||||
return "mixed";
|
||||
}
|
||||
|
||||
function isDateDue(removeAfter: string, today = new Date()): boolean {
|
||||
return new Date(`${removeAfter}T00:00:00Z`) <= today;
|
||||
}
|
||||
|
||||
function buildSummary(report: BoundaryReport, owner?: string): BoundaryReportSummary {
|
||||
const eligibleForRemoval = report.compat.records
|
||||
.filter((record) => record.eligibleForRemoval)
|
||||
@@ -410,6 +420,10 @@ function buildSummary(report: BoundaryReport, owner?: string): BoundaryReportSum
|
||||
dormantReservedCountInUnused: report.pluginSdk.dormantReservedSubpaths.length,
|
||||
unclassifiedUnusedReservedCount: report.pluginSdk.unclassifiedUnusedReservedSubpaths.length,
|
||||
unclassifiedUnusedReservedSubpaths: report.pluginSdk.unclassifiedUnusedReservedSubpaths,
|
||||
dormantReservedEligibleForRemovalCount:
|
||||
report.pluginSdk.dormantReservedEligibleForRemovalSubpaths.length,
|
||||
dormantReservedEligibleForRemovalSubpaths:
|
||||
report.pluginSdk.dormantReservedEligibleForRemovalSubpaths,
|
||||
crossOwnerReservedImports: report.pluginSdk.crossOwnerReservedImports,
|
||||
},
|
||||
memoryHostSdk: {
|
||||
@@ -434,6 +448,9 @@ function buildReport(options: Pick<CliOptions, "owner"> = {}): BoundaryReport {
|
||||
);
|
||||
const usedReserved = new Set(reservedImports.map((entry) => entry.subpath));
|
||||
const dormantReserved = new Set<string>(dormantReservedBundledPluginSdkEntrypoints);
|
||||
const dormantReservedRecords = dormantReservedBundledPluginSdkEntrypointRecords.filter((record) =>
|
||||
matchesOwner(options.owner, record.owner),
|
||||
);
|
||||
const unusedReservedSubpaths = reservedBundledPluginSdkEntrypoints
|
||||
.filter(
|
||||
(subpath) =>
|
||||
@@ -444,6 +461,11 @@ function buildReport(options: Pick<CliOptions, "owner"> = {}): BoundaryReport {
|
||||
const dormantReservedSubpaths = unusedReservedSubpaths
|
||||
.filter((subpath) => dormantReserved.has(subpath))
|
||||
.toSorted();
|
||||
const dormantReservedEligibleForRemovalSubpaths = dormantReservedRecords
|
||||
.filter((record) => unusedReservedSubpaths.includes(record.subpath))
|
||||
.filter((record) => isDateDue(record.removeAfter))
|
||||
.map((record) => record.subpath)
|
||||
.toSorted();
|
||||
return {
|
||||
generatedAt: new Date().toISOString(),
|
||||
compat: {
|
||||
@@ -463,9 +485,11 @@ function buildReport(options: Pick<CliOptions, "owner"> = {}): BoundaryReport {
|
||||
),
|
||||
unusedReservedSubpaths,
|
||||
dormantReservedSubpaths,
|
||||
dormantReservedRecords,
|
||||
unclassifiedUnusedReservedSubpaths: unusedReservedSubpaths
|
||||
.filter((subpath) => !dormantReserved.has(subpath))
|
||||
.toSorted(),
|
||||
dormantReservedEligibleForRemovalSubpaths,
|
||||
},
|
||||
memoryHostSdk: collectMemoryHostBoundary(files),
|
||||
};
|
||||
@@ -487,9 +511,15 @@ function renderSummaryText(summary: BoundaryReportSummary): string {
|
||||
lines.push(
|
||||
` dormantUnused=${summary.pluginSdk.dormantReservedCountInUnused} unclassifiedUnused=${summary.pluginSdk.unclassifiedUnusedReservedCount}`,
|
||||
);
|
||||
lines.push(
|
||||
` dormantEligibleForRemoval=${summary.pluginSdk.dormantReservedEligibleForRemovalCount}`,
|
||||
);
|
||||
for (const subpath of summary.pluginSdk.unclassifiedUnusedReservedSubpaths) {
|
||||
lines.push(` unclassified-unused ${subpath}`);
|
||||
}
|
||||
for (const subpath of summary.pluginSdk.dormantReservedEligibleForRemovalSubpaths) {
|
||||
lines.push(` dormant-due ${subpath}`);
|
||||
}
|
||||
for (const entry of summary.pluginSdk.crossOwnerReservedImports) {
|
||||
lines.push(` cross-owner ${entry.file}: ${entry.specifier} owner=${entry.owner ?? "unknown"}`);
|
||||
}
|
||||
@@ -521,9 +551,15 @@ function renderText(report: BoundaryReport, owner?: string): string {
|
||||
lines.push(
|
||||
` dormantUnused=${report.pluginSdk.dormantReservedSubpaths.length} unclassifiedUnused=${report.pluginSdk.unclassifiedUnusedReservedSubpaths.length}`,
|
||||
);
|
||||
lines.push(
|
||||
` dormantEligibleForRemoval=${report.pluginSdk.dormantReservedEligibleForRemovalSubpaths.length}`,
|
||||
);
|
||||
for (const subpath of report.pluginSdk.unclassifiedUnusedReservedSubpaths) {
|
||||
lines.push(` unclassified-unused ${subpath}`);
|
||||
}
|
||||
for (const subpath of report.pluginSdk.dormantReservedEligibleForRemovalSubpaths) {
|
||||
lines.push(` dormant-due ${subpath}`);
|
||||
}
|
||||
for (const entry of report.pluginSdk.crossOwnerReservedImports) {
|
||||
lines.push(` cross-owner ${entry.file}: ${entry.specifier} owner=${entry.owner ?? "unknown"}`);
|
||||
}
|
||||
@@ -554,6 +590,14 @@ function collectFailures(report: BoundaryReport, options: CliOptions): string[]
|
||||
`${report.compat.eligibleForRemovalCount} compatibility record(s) are due for removal`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
options.failOnEligibleCompat &&
|
||||
report.pluginSdk.dormantReservedEligibleForRemovalSubpaths.length > 0
|
||||
) {
|
||||
failures.push(
|
||||
`${report.pluginSdk.dormantReservedEligibleForRemovalSubpaths.length} dormant reserved SDK subpath(s) are due for removal`,
|
||||
);
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,53 +60,327 @@ export const reservedBundledPluginSdkEntrypoints = [
|
||||
"zalouser",
|
||||
] as const;
|
||||
|
||||
export type DormantReservedBundledPluginSdkEntrypointReason =
|
||||
| "bundled-plugin-compat"
|
||||
| "external-compat"
|
||||
| "owner-facade-compat";
|
||||
|
||||
export type DormantReservedBundledPluginSdkEntrypointRecord = {
|
||||
subpath: string;
|
||||
owner: string;
|
||||
reason: DormantReservedBundledPluginSdkEntrypointReason;
|
||||
removeAfter: "2026-07-24";
|
||||
replacement: string;
|
||||
};
|
||||
|
||||
// Reserved compatibility/helper subpaths with no current tracked imports.
|
||||
// Keeping them classified avoids treating dormant compatibility as unknown debt.
|
||||
export const dormantReservedBundledPluginSdkEntrypoints = [
|
||||
"bluebubbles",
|
||||
"bluebubbles-policy",
|
||||
"browser-cdp",
|
||||
"browser-control-auth",
|
||||
"browser-profiles",
|
||||
"browser-support",
|
||||
"diagnostics-otel",
|
||||
"diagnostics-prometheus",
|
||||
"diffs",
|
||||
"feishu",
|
||||
"feishu-conversation",
|
||||
"feishu-setup",
|
||||
"github-copilot-login",
|
||||
"googlechat",
|
||||
"googlechat-runtime-shared",
|
||||
"irc",
|
||||
"irc-surface",
|
||||
"line",
|
||||
"line-core",
|
||||
"line-runtime",
|
||||
"line-surface",
|
||||
"llm-task",
|
||||
"matrix",
|
||||
"matrix-helper",
|
||||
"matrix-runtime-heavy",
|
||||
"matrix-runtime-surface",
|
||||
"matrix-surface",
|
||||
"matrix-thread-bindings",
|
||||
"mattermost",
|
||||
"mattermost-policy",
|
||||
"memory-lancedb",
|
||||
"msteams",
|
||||
"nextcloud-talk",
|
||||
"nostr",
|
||||
"opencode",
|
||||
"telegram-command-ui",
|
||||
"thread-ownership",
|
||||
"tlon",
|
||||
"twitch",
|
||||
"voice-call",
|
||||
"zalo",
|
||||
"zalo-setup",
|
||||
"zalouser",
|
||||
] as const;
|
||||
export const dormantReservedBundledPluginSdkEntrypointRecords = [
|
||||
{
|
||||
subpath: "bluebubbles",
|
||||
owner: "bluebubbles",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "BlueBubbles local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "bluebubbles-policy",
|
||||
owner: "bluebubbles",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "BlueBubbles local api/runtime-api plus plugin-sdk/channel-policy",
|
||||
},
|
||||
{
|
||||
subpath: "browser-cdp",
|
||||
owner: "browser",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "plugin-sdk/browser-config plus browser local config helpers",
|
||||
},
|
||||
{
|
||||
subpath: "browser-control-auth",
|
||||
owner: "browser",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "plugin-sdk/browser-config plus browser local control-auth helpers",
|
||||
},
|
||||
{
|
||||
subpath: "browser-profiles",
|
||||
owner: "browser",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "plugin-sdk/browser-config plus browser local profile helpers",
|
||||
},
|
||||
{
|
||||
subpath: "browser-support",
|
||||
owner: "browser",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "focused browser SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "diagnostics-otel",
|
||||
owner: "diagnostics-otel",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "diagnostics-otel local api plus plugin-sdk/diagnostic-runtime",
|
||||
},
|
||||
{
|
||||
subpath: "diagnostics-prometheus",
|
||||
owner: "diagnostics-prometheus",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "diagnostics-prometheus local api plus plugin-sdk/diagnostic-runtime",
|
||||
},
|
||||
{
|
||||
subpath: "diffs",
|
||||
owner: "diffs",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "diffs local api/runtime-api plus generic plugin SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "feishu",
|
||||
owner: "feishu",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Feishu local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "feishu-conversation",
|
||||
owner: "feishu",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Feishu local contract-api plus plugin-sdk/conversation-runtime",
|
||||
},
|
||||
{
|
||||
subpath: "feishu-setup",
|
||||
owner: "feishu",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Feishu local setup-api plus plugin-sdk/channel-setup",
|
||||
},
|
||||
{
|
||||
subpath: "github-copilot-login",
|
||||
owner: "github-copilot",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "GitHub Copilot local api plus plugin-sdk/provider-auth-login",
|
||||
},
|
||||
{
|
||||
subpath: "googlechat",
|
||||
owner: "googlechat",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Google Chat local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "googlechat-runtime-shared",
|
||||
owner: "googlechat",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Google Chat local runtime-api plus plugin-sdk/config-types",
|
||||
},
|
||||
{
|
||||
subpath: "irc",
|
||||
owner: "irc",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "IRC local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "irc-surface",
|
||||
owner: "irc",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "IRC local api plus plugin-sdk/channel-setup",
|
||||
},
|
||||
{
|
||||
subpath: "line",
|
||||
owner: "line",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "LINE local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "line-core",
|
||||
owner: "line",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "LINE local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "line-runtime",
|
||||
owner: "line",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "LINE local runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "line-surface",
|
||||
owner: "line",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "LINE local runtime-api plus plugin-sdk/channel-setup",
|
||||
},
|
||||
{
|
||||
subpath: "llm-task",
|
||||
owner: "llm-task",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "llm-task local api plus plugin-sdk/plugin-entry",
|
||||
},
|
||||
{
|
||||
subpath: "matrix",
|
||||
owner: "matrix",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Matrix local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "matrix-helper",
|
||||
owner: "matrix",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Matrix local api plus plugin-sdk/config-types",
|
||||
},
|
||||
{
|
||||
subpath: "matrix-runtime-heavy",
|
||||
owner: "matrix",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Matrix local runtime-api plus doctor/fix migration paths",
|
||||
},
|
||||
{
|
||||
subpath: "matrix-runtime-surface",
|
||||
owner: "matrix",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Matrix local runtime-api plus plugin-sdk/config-types",
|
||||
},
|
||||
{
|
||||
subpath: "matrix-surface",
|
||||
owner: "matrix",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Matrix local contract/runtime API plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "matrix-thread-bindings",
|
||||
owner: "matrix",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Matrix local api plus plugin-sdk/thread-bindings-runtime",
|
||||
},
|
||||
{
|
||||
subpath: "mattermost",
|
||||
owner: "mattermost",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Mattermost local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "mattermost-policy",
|
||||
owner: "mattermost",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Mattermost local policy-api plus plugin-sdk/channel-policy",
|
||||
},
|
||||
{
|
||||
subpath: "memory-lancedb",
|
||||
owner: "memory-lancedb",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "memory-lancedb local api plus plugin-sdk/plugin-entry",
|
||||
},
|
||||
{
|
||||
subpath: "msteams",
|
||||
owner: "msteams",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Microsoft Teams local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "nextcloud-talk",
|
||||
owner: "nextcloud-talk",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Nextcloud Talk local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "nostr",
|
||||
owner: "nostr",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Nostr local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "opencode",
|
||||
owner: "opencode",
|
||||
reason: "external-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "plugin-sdk/provider-auth-api-key plus OpenCode local provider helpers",
|
||||
},
|
||||
{
|
||||
subpath: "telegram-command-ui",
|
||||
owner: "telegram",
|
||||
reason: "external-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "plugin-sdk/telegram-command-config plus Telegram local command UI helpers",
|
||||
},
|
||||
{
|
||||
subpath: "thread-ownership",
|
||||
owner: "thread-ownership",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "thread-ownership local api plus plugin-sdk/plugin-entry",
|
||||
},
|
||||
{
|
||||
subpath: "tlon",
|
||||
owner: "tlon",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Tlon local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "twitch",
|
||||
owner: "twitch",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Twitch local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "voice-call",
|
||||
owner: "voice-call",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Voice Call local api plus plugin-sdk/plugin-entry",
|
||||
},
|
||||
{
|
||||
subpath: "zalo",
|
||||
owner: "zalo",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Zalo local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
{
|
||||
subpath: "zalo-setup",
|
||||
owner: "zalo",
|
||||
reason: "owner-facade-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Zalo local setup/contract APIs plus plugin-sdk/channel-setup",
|
||||
},
|
||||
{
|
||||
subpath: "zalouser",
|
||||
owner: "zalouser",
|
||||
reason: "bundled-plugin-compat",
|
||||
removeAfter: "2026-07-24",
|
||||
replacement: "Zalo user local api/runtime-api plus generic channel SDK subpaths",
|
||||
},
|
||||
] as const satisfies readonly DormantReservedBundledPluginSdkEntrypointRecord[];
|
||||
|
||||
export const dormantReservedBundledPluginSdkEntrypoints =
|
||||
dormantReservedBundledPluginSdkEntrypointRecords.map((record) => record.subpath);
|
||||
|
||||
// Supported SDK facades backed by bundled plugins. These are intentionally public
|
||||
// until they move to generic, plugin-neutral contracts.
|
||||
|
||||
@@ -4,6 +4,7 @@ import { fileURLToPath } from "node:url";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
dormantReservedBundledPluginSdkEntrypoints,
|
||||
dormantReservedBundledPluginSdkEntrypointRecords,
|
||||
pluginSdkEntrypoints,
|
||||
publicPluginOwnedSdkEntrypoints,
|
||||
reservedBundledPluginSdkEntrypoints,
|
||||
@@ -514,6 +515,42 @@ function collectReservedSdkSubpathImports(): string[] {
|
||||
return [...imports].toSorted();
|
||||
}
|
||||
|
||||
function collectDormantReservedMetadataDrift(): string[] {
|
||||
const failures: string[] = [];
|
||||
const recordsBySubpath = new Map<
|
||||
string,
|
||||
(typeof dormantReservedBundledPluginSdkEntrypointRecords)[number]
|
||||
>();
|
||||
for (const record of dormantReservedBundledPluginSdkEntrypointRecords) {
|
||||
if (recordsBySubpath.has(record.subpath)) {
|
||||
failures.push(`${record.subpath}: duplicate dormant metadata record`);
|
||||
continue;
|
||||
}
|
||||
recordsBySubpath.set(record.subpath, record);
|
||||
if (record.replacement.trim().length === 0) {
|
||||
failures.push(`${record.subpath}: missing replacement`);
|
||||
}
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(record.removeAfter)) {
|
||||
failures.push(`${record.subpath}: invalid removeAfter ${record.removeAfter}`);
|
||||
}
|
||||
if (record.owner.trim().length === 0) {
|
||||
failures.push(`${record.subpath}: missing owner`);
|
||||
}
|
||||
const resolvedOwner = resolvePluginOwnerFromEntrypoint(record.subpath);
|
||||
if (resolvedOwner && resolvedOwner !== record.owner) {
|
||||
failures.push(`${record.subpath}: owner ${record.owner} should be ${resolvedOwner}`);
|
||||
}
|
||||
}
|
||||
|
||||
const recordSubpaths = [...recordsBySubpath.keys()].toSorted();
|
||||
const derivedSubpaths = [...dormantReservedBundledPluginSdkEntrypoints].toSorted();
|
||||
if (JSON.stringify(recordSubpaths) !== JSON.stringify(derivedSubpaths)) {
|
||||
failures.push("dormant subpath list must be derived from dormant metadata records");
|
||||
}
|
||||
|
||||
return failures.toSorted();
|
||||
}
|
||||
|
||||
describe("plugin-sdk package contract guardrails", () => {
|
||||
it("keeps plugin-sdk entrypoint metadata unique", () => {
|
||||
const counts = new Map<string, number>();
|
||||
@@ -564,6 +601,10 @@ describe("plugin-sdk package contract guardrails", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps dormant reserved SDK compatibility subpaths annotated for retirement", () => {
|
||||
expect(collectDormantReservedMetadataDrift()).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps plugin-owned SDK subpaths explicitly classified and documented", () => {
|
||||
const entrypoints = new Set(pluginSdkEntrypoints);
|
||||
const reserved = new Set<string>(reservedBundledPluginSdkEntrypoints);
|
||||
|
||||
@@ -27,6 +27,7 @@ describe("plugin-boundary-report", () => {
|
||||
const summary = JSON.parse(output) as {
|
||||
pluginSdk?: {
|
||||
crossOwnerReservedImportCount?: unknown;
|
||||
dormantReservedEligibleForRemovalCount?: unknown;
|
||||
unclassifiedUnusedReservedCount?: unknown;
|
||||
};
|
||||
memoryHostSdk?: {
|
||||
@@ -35,6 +36,7 @@ describe("plugin-boundary-report", () => {
|
||||
};
|
||||
|
||||
expect(summary.pluginSdk?.crossOwnerReservedImportCount).toBe(0);
|
||||
expect(summary.pluginSdk?.dormantReservedEligibleForRemovalCount).toBe(0);
|
||||
expect(summary.pluginSdk?.unclassifiedUnusedReservedCount).toBe(0);
|
||||
expect(summary.memoryHostSdk?.implementation).toBe("private-core-bridge");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user