

















@@ -30,6 +30,7 @@ const PLUGIN_SDK_SPECIFIER_PATTERN =
3030type CliOptions = {
3131json: boolean;
3232 summary: boolean;
33+ retirementPlan: boolean;
3334owner?: string;
3435 failOnCrossOwner: boolean;
3536 failOnEligibleCompat: boolean;
@@ -162,6 +163,7 @@ function parseArgs(args: readonly string[]): CliOptions {
162163const options: CliOptions = {
163164json: false,
164165summary: false,
166+retirementPlan: false,
165167failOnCrossOwner: false,
166168failOnEligibleCompat: false,
167169failOnUnclassifiedUnusedReserved: false,
@@ -173,6 +175,8 @@ function parseArgs(args: readonly string[]): CliOptions {
173175options.json = true;
174176} else if (arg === "--summary") {
175177options.summary = true;
178+} else if (arg === "--retirement-plan") {
179+options.retirementPlan = true;
176180} else if (arg === "--owner") {
177181const owner = args[index + 1];
178182if (!owner || owner.startsWith("--")) {
@@ -192,6 +196,9 @@ function parseArgs(args: readonly string[]): CliOptions {
192196throw new Error(`Unknown argument: ${arg}`);
193197}
194198}
199+if (options.retirementPlan && (options.json || options.summary)) {
200+throw new Error("--retirement-plan cannot be combined with --summary or --json");
201+}
195202return options;
196203}
197204@@ -202,6 +209,7 @@ function renderHelp(): string {
202209"Options:",
203210" --summary Print compact counts only.",
204211" --json Emit JSON instead of text.",
212+" --retirement-plan Emit an issue/PR-ready dormant SDK subpath retirement checklist.",
205213" --owner <id> Filter compat/imports/reserved shims by owner id.",
206214" --fail-on-cross-owner Exit non-zero on cross-owner reserved SDK imports.",
207215" --fail-on-eligible-compat Exit non-zero when deprecated compat is due for removal.",
@@ -570,6 +578,49 @@ function renderText(report: BoundaryReport, owner?: string): string {
570578return lines.join("\n");
571579}
572580581+function renderRetirementPlan(report: BoundaryReport, owner?: string): string {
582+const records = report.pluginSdk.dormantReservedRecords.toSorted(
583+(left, right) =>
584+left.owner.localeCompare(right.owner) ||
585+left.removeAfter.localeCompare(right.removeAfter) ||
586+left.subpath.localeCompare(right.subpath),
587+);
588+const dueSubpaths = new Set(report.pluginSdk.dormantReservedEligibleForRemovalSubpaths);
589+const owners = [...new Set(records.map((record) => record.owner))];
590+const removeAfterDates = [...new Set(records.map((record) => record.removeAfter))];
591+const lines: string[] = [];
592+lines.push(`# Plugin SDK Dormant Reserved Subpath Retirement Plan`);
593+lines.push("");
594+lines.push(`Generated: ${report.generatedAt}`);
595+if (owner) {
596+lines.push(`Owner filter: \`${owner}\``);
597+}
598+lines.push("");
599+lines.push("## Summary");
600+lines.push("");
601+lines.push(`- Dormant reserved subpaths: ${records.length}`);
602+lines.push(`- Owners: ${owners.length}`);
603+lines.push(`- Removal dates: ${removeAfterDates.join(", ") || "none"}`);
604+lines.push(`- Eligible for removal now: ${dueSubpaths.size}`);
605+lines.push(`- CI gate: \`pnpm plugins:boundary-report:ci\``);
606+if (records.length === 0) {
607+lines.push("");
608+lines.push("No dormant reserved SDK subpaths match this filter.");
609+return lines.join("\n");
610+}
611+for (const ownerId of owners) {
612+lines.push("");
613+lines.push(`## ${ownerId}`);
614+for (const record of records.filter((candidate) => candidate.owner === ownerId)) {
615+const status = dueSubpaths.has(record.subpath) ? "due" : "waiting";
616+lines.push(
617+`- [ ] \`openclaw/plugin-sdk/${record.subpath}\` remove after \`${record.removeAfter}\` (${status}); reason=\`${record.reason}\`; replacement: ${record.replacement}`,
618+);
619+}
620+}
621+return lines.join("\n");
622+}
623+573624function collectFailures(report: BoundaryReport, options: CliOptions): string[] {
574625const failures: string[] = [];
575626if (options.failOnCrossOwner && report.pluginSdk.crossOwnerReservedImports.length > 0) {
@@ -618,7 +669,9 @@ if (options.help) {
618669619670const report = buildReport(options);
620671const summary = buildSummary(report, options.owner);
621-if (options.json) {
672+if (options.retirementPlan) {
673+process.stdout.write(`${renderRetirementPlan(report, options.owner)}\n`);
674+} else if (options.json) {
622675process.stdout.write(`${JSON.stringify(options.summary ? summary : report, null, 2)}\n`);
623676} else if (options.summary) {
624677process.stdout.write(`${renderSummaryText(summary)}\n`);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。