






















@@ -1,7 +1,7 @@
11import { describe, expect, it } from "vitest";
22import type { MigrationItem, MigrationPlan } from "../../plugins/types.js";
33import { stripAnsi } from "../../terminal/ansi.js";
4-import { formatMigrationPlan } from "./output.js";
4+import { formatMigrationPreview, formatMigrationResult } from "./output.js";
5566function skillItem(index: number): MigrationItem {
77return {
@@ -29,6 +29,15 @@ function pluginItem(name: string): MigrationItem {
2929};
3030}
313132+function configItem(): MigrationItem {
33+return {
34+id: "config:codex-plugins-root",
35+kind: "config",
36+action: "update",
37+status: "planned",
38+};
39+}
40+3241function plan(items: MigrationItem[]): MigrationPlan {
3342return {
3443providerId: "codex",
@@ -46,27 +55,61 @@ function plan(items: MigrationItem[]): MigrationPlan {
4655};
4756}
485749-describe("formatMigrationPlan", () => {
50-it("does not duplicate native Codex plugins when they are already visible", () => {
51-const lines = formatMigrationPlan(
58+describe("formatMigrationPreview", () => {
59+it("groups items under per-kind headings", () => {
60+const output = formatMigrationPreview(
5261plan([skillItem(1), pluginItem("google-calendar"), pluginItem("gmail")]),
53-).map(stripAnsi);
62+)
63+.map(stripAnsi)
64+.join("\n");
65+66+expect(output).toContain("Skills:");
67+expect(output).toContain("Plugins:");
68+expect(output).not.toContain("Native Codex plugins:");
69+expect(output).toContain("• skill-1");
70+expect(output).toContain("• google-calendar");
71+expect(output).toContain("• gmail");
72+});
73+74+it("hides config items from display and excludes them from the count", () => {
75+const output = formatMigrationPreview(plan([skillItem(1), configItem()]))
76+.map(stripAnsi)
77+.join("\n");
78+79+expect(output).toContain("1 item, 0 conflicts, 0 sensitive items");
80+expect(output).not.toContain("Config:");
81+expect(output).not.toContain("codex-plugins-root");
82+});
83+});
84+85+describe("formatMigrationResult", () => {
86+it("renders a check glyph and (Migrated) for migrated items", () => {
87+const output = formatMigrationResult(plan([{ ...skillItem(1), status: "migrated" }]))
88+.map(stripAnsi)
89+.join("\n");
90+91+expect(output).toContain("✅");
92+expect(output).toContain("(Migrated)");
93+});
94+95+it("humanizes known error reason codes", () => {
96+const output = formatMigrationResult(
97+plan([{ ...pluginItem("google-calendar"), status: "error", reason: "plugin_missing" }]),
98+)
99+.map(stripAnsi)
100+.join("\n");
5410155-expect(lines.join("\n")).not.toContain("Native Codex plugins:");
102+expect(output).toContain("❌");
103+expect(output).toContain("Plugin not found in the Codex marketplace.");
56104});
5710558-it("surfaces native Codex plugin names even when normal item output is truncated", () => {
59-const lines = formatMigrationPlan(
60-plan([
61- ...Array.from({ length: 30 }, (_, index) => skillItem(index + 1)),
62-pluginItem("google-calendar"),
63-pluginItem("gmail"),
64-]),
65-).map(stripAnsi);
106+it("says (Skipped) for user-deselected skill/plugin items", () => {
107+const output = formatMigrationResult(
108+plan([{ ...skillItem(1), status: "skipped", reason: "not selected for migration" }]),
109+)
110+.map(stripAnsi)
111+.join("\n");
6611267-const output = lines.join("\n");
68-expect(output).toContain("Native Codex plugins:\n- google-calendar\n- gmail");
69-expect(output.indexOf("Native Codex plugins:")).toBeLessThan(output.indexOf("Items:"));
70-expect(output).toContain("- ... 7 more");
113+expect(output).toContain("(Skipped)");
71114});
72115});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。