From 5190843f8f09ac17cbf79561bd1f708c509cda78 Mon Sep 17 00:00:00 2001 From: Kaoru0822 <208281322+kaoru0822-kitauji@users.noreply.github.com> Date: Mon, 12 Oct 2026 04:55:15 -0700 Subject: [PATCH] fix(setup): name each skill directory in the uninstall summary (#2118) Uninstall checks every skill destination but labeled each result only as "skill" (or "Claude Code skill"), so a retained or failed destination could not be located. Label each result with the directory it refers to. Fixes #2111 Co-authored-by: Claude Opus 5.5 --- src/application/Uninstall.ts | 11 ++---- .../cli/clientProfileLifecycle.test.ts | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/application/Uninstall.ts b/src/application/Uninstall.ts index 9880c8cb9..6822460bb 100644 --- a/src/application/Uninstall.ts +++ b/src/application/Uninstall.ts @@ -504,14 +504,11 @@ const removeManagedSkills = async ( environment: Readonly, platform: NodeJS.Platform, ): Promise => { + // Every destination shares one summary item, so each result is labeled by + // the directory it refers to. const results = await Promise.all( - skillDestinations(home, undefined, environment, platform).map( - ({ client, path }) => - removeManagedSkill( - path, - client === "claude_code" ? "Claude Code skill" : "skill", - fileSystem, - ), + skillDestinations(home, undefined, environment, platform).map(({ path }) => + removeManagedSkill(path, path, fileSystem), ), ); const failed = results.find(({ status }) => status === "failed"); diff --git a/tests/boundary/cli/clientProfileLifecycle.test.ts b/tests/boundary/cli/clientProfileLifecycle.test.ts index 531e6378a..4fd566fd7 100644 --- a/tests/boundary/cli/clientProfileLifecycle.test.ts +++ b/tests/boundary/cli/clientProfileLifecycle.test.ts @@ -9,6 +9,7 @@ import { } from "node:fs/promises"; import { join } from "node:path"; import { expect } from "vitest"; +import { PRODUCT_IDENTITY } from "../../../src/identity.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { cliTest } from "../../support/cli/cliFixture.js"; @@ -259,3 +260,39 @@ for (const group of groups) { }, ); } + +cliTest("uninstall names each retained skill directory", async ({ cli }) => { + const home = await createTestTempDirectory("rea-uninstall-skill-paths-"); + const shared = join(home, ".agents", "skills", PRODUCT_IDENTITY.skillName); + const claude = join(home, ".claude", "skills", PRODUCT_IDENTITY.skillName); + for (const directory of [shared, claude]) { + await mkdir(directory, { recursive: true }); + await writeFile(join(directory, "SKILL.md"), "---\nname: unrelated\n---\n"); + } + + const result = await cli.run({ + arguments: ["uninstall", "--json"], + cwd: home, + environment: { + HOME: home, + USERPROFILE: home, + CLAUDE_CONFIG_DIR: join(home, ".claude"), + }, + timeoutMs: 20_000, + }); + + expect(result.exitCode, result.stderr).toBe(0); + const report = result.json as { + items?: readonly { name: string; status: string; detail: string }[]; + }; + const skill = report.items?.find(({ name }) => name === "skill"); + expect(skill?.status).toBe("retained"); + for (const directory of [shared, claude]) { + expect(skill?.detail).toContain( + `${directory}: retained (Skill manifest is not REA-owned.)`, + ); + expect(await readFile(join(directory, "SKILL.md"), "utf8")).toBe( + "---\nname: unrelated\n---\n", + ); + } +});